xref: /titanic_50/usr/src/lib/libproc/common/Pzone.c (revision a7e1d0d300de20869e70883ddfa4a5ca867ce135)
1186f7fbfSEdward Pilatowicz /*
2186f7fbfSEdward Pilatowicz  * CDDL HEADER START
3186f7fbfSEdward Pilatowicz  *
4186f7fbfSEdward Pilatowicz  * The contents of this file are subject to the terms of the
5186f7fbfSEdward Pilatowicz  * Common Development and Distribution License (the "License").
6186f7fbfSEdward Pilatowicz  * You may not use this file except in compliance with the License.
7186f7fbfSEdward Pilatowicz  *
8186f7fbfSEdward Pilatowicz  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9186f7fbfSEdward Pilatowicz  * or http://www.opensolaris.org/os/licensing.
10186f7fbfSEdward Pilatowicz  * See the License for the specific language governing permissions
11186f7fbfSEdward Pilatowicz  * and limitations under the License.
12186f7fbfSEdward Pilatowicz  *
13186f7fbfSEdward Pilatowicz  * When distributing Covered Code, include this CDDL HEADER in each
14186f7fbfSEdward Pilatowicz  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15186f7fbfSEdward Pilatowicz  * If applicable, add the following below this CDDL HEADER, with the
16186f7fbfSEdward Pilatowicz  * fields enclosed by brackets "[]" replaced with your own identifying
17186f7fbfSEdward Pilatowicz  * information: Portions Copyright [yyyy] [name of copyright owner]
18186f7fbfSEdward Pilatowicz  *
19186f7fbfSEdward Pilatowicz  * CDDL HEADER END
20186f7fbfSEdward Pilatowicz  */
21186f7fbfSEdward Pilatowicz 
22186f7fbfSEdward Pilatowicz /*
23*a7e1d0d3SRoger A. Faulkner  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24186f7fbfSEdward Pilatowicz  * Use is subject to license terms.
25186f7fbfSEdward Pilatowicz  */
26186f7fbfSEdward Pilatowicz 
27186f7fbfSEdward Pilatowicz #include <assert.h>
28186f7fbfSEdward Pilatowicz #include <dlfcn.h>
29186f7fbfSEdward Pilatowicz #include <errno.h>
30186f7fbfSEdward Pilatowicz #include <libzonecfg.h>
31186f7fbfSEdward Pilatowicz #include <link.h>
32186f7fbfSEdward Pilatowicz #include <string.h>
33186f7fbfSEdward Pilatowicz #include <strings.h>
34186f7fbfSEdward Pilatowicz #include <sys/list.h>
35186f7fbfSEdward Pilatowicz #include <sys/types.h>
36186f7fbfSEdward Pilatowicz #include <sys/mkdev.h>
37186f7fbfSEdward Pilatowicz #include <sys/mman.h>
38186f7fbfSEdward Pilatowicz #include <sys/mnttab.h>
39186f7fbfSEdward Pilatowicz 
40186f7fbfSEdward Pilatowicz #include "Pcontrol.h"
41186f7fbfSEdward Pilatowicz 
42186f7fbfSEdward Pilatowicz struct path_node {
43186f7fbfSEdward Pilatowicz 	struct path_node	*pn_next;
44186f7fbfSEdward Pilatowicz 	char			*pn_path;
45186f7fbfSEdward Pilatowicz };
46186f7fbfSEdward Pilatowicz typedef struct path_node path_node_t;
47186f7fbfSEdward Pilatowicz 
48*a7e1d0d3SRoger A. Faulkner /*
49*a7e1d0d3SRoger A. Faulkner  * Parameters of the lofs lookup cache.
50*a7e1d0d3SRoger A. Faulkner  */
51*a7e1d0d3SRoger A. Faulkner static struct stat64 lofs_mstat; /* last stat() of MNTTAB */
52*a7e1d0d3SRoger A. Faulkner static struct lofs_mnttab {	/* linked list of all lofs mount points */
53*a7e1d0d3SRoger A. Faulkner 	struct lofs_mnttab *l_next;
54*a7e1d0d3SRoger A. Faulkner 	char	*l_special;	/* extracted from MNTTAB */
55*a7e1d0d3SRoger A. Faulkner 	char	*l_mountp;	/* ditto */
56*a7e1d0d3SRoger A. Faulkner } *lofs_mnttab = NULL;
57*a7e1d0d3SRoger A. Faulkner static mutex_t lofs_lock = DEFAULTMUTEX;	/* protects the lofs cache */
58*a7e1d0d3SRoger A. Faulkner 
59*a7e1d0d3SRoger A. Faulkner static void
60*a7e1d0d3SRoger A. Faulkner rebuild_lofs_cache(void)
61*a7e1d0d3SRoger A. Faulkner {
62*a7e1d0d3SRoger A. Faulkner 	struct mnttab mt;
63*a7e1d0d3SRoger A. Faulkner 	struct mnttab mt_find;
64*a7e1d0d3SRoger A. Faulkner 	struct lofs_mnttab *lmt;
65*a7e1d0d3SRoger A. Faulkner 	struct lofs_mnttab *next;
66*a7e1d0d3SRoger A. Faulkner 	FILE *fp;
67*a7e1d0d3SRoger A. Faulkner 
68*a7e1d0d3SRoger A. Faulkner 	assert(MUTEX_HELD(&lofs_lock));
69*a7e1d0d3SRoger A. Faulkner 
70*a7e1d0d3SRoger A. Faulkner 	/* destroy the old cache */
71*a7e1d0d3SRoger A. Faulkner 	for (lmt = lofs_mnttab; lmt != NULL; lmt = next) {
72*a7e1d0d3SRoger A. Faulkner 		next = lmt->l_next;
73*a7e1d0d3SRoger A. Faulkner 		free(lmt->l_special);
74*a7e1d0d3SRoger A. Faulkner 		free(lmt->l_mountp);
75*a7e1d0d3SRoger A. Faulkner 		free(lmt);
76*a7e1d0d3SRoger A. Faulkner 	}
77*a7e1d0d3SRoger A. Faulkner 	lofs_mnttab = NULL;
78*a7e1d0d3SRoger A. Faulkner 
79*a7e1d0d3SRoger A. Faulkner 	/* prepare to create the new cache */
80*a7e1d0d3SRoger A. Faulkner 	if ((fp = fopen(MNTTAB, "r")) == NULL)
81*a7e1d0d3SRoger A. Faulkner 		return;
82*a7e1d0d3SRoger A. Faulkner 
83*a7e1d0d3SRoger A. Faulkner 	/*
84*a7e1d0d3SRoger A. Faulkner 	 * We only care about lofs mount points.  But we need to
85*a7e1d0d3SRoger A. Faulkner 	 * ignore lofs mounts where the source path is the same
86*a7e1d0d3SRoger A. Faulkner 	 * as the target path.  (This can happen when a non-global
87*a7e1d0d3SRoger A. Faulkner 	 * zone has a lofs mount of a global zone filesystem, since
88*a7e1d0d3SRoger A. Faulkner 	 * the source path can't expose information about global
89*a7e1d0d3SRoger A. Faulkner 	 * zone paths to the non-global zone.)
90*a7e1d0d3SRoger A. Faulkner 	 */
91*a7e1d0d3SRoger A. Faulkner 	bzero(&mt_find, sizeof (mt_find));
92*a7e1d0d3SRoger A. Faulkner 	mt_find.mnt_fstype = "lofs";
93*a7e1d0d3SRoger A. Faulkner 	while (getmntany(fp, &mt, &mt_find) == 0 &&
94*a7e1d0d3SRoger A. Faulkner 	    (strcmp(mt.mnt_fstype, "lofs") == 0) &&
95*a7e1d0d3SRoger A. Faulkner 	    (strcmp(mt.mnt_special, mt.mnt_mountp) != 0)) {
96*a7e1d0d3SRoger A. Faulkner 		if ((lmt = malloc(sizeof (struct lofs_mnttab))) == NULL)
97*a7e1d0d3SRoger A. Faulkner 			break;
98*a7e1d0d3SRoger A. Faulkner 		lmt->l_special = strdup(mt.mnt_special);
99*a7e1d0d3SRoger A. Faulkner 		lmt->l_mountp = strdup(mt.mnt_mountp);
100*a7e1d0d3SRoger A. Faulkner 		lmt->l_next = lofs_mnttab;
101*a7e1d0d3SRoger A. Faulkner 		lofs_mnttab = lmt;
102*a7e1d0d3SRoger A. Faulkner 	}
103*a7e1d0d3SRoger A. Faulkner 
104*a7e1d0d3SRoger A. Faulkner 	(void) fclose(fp);
105*a7e1d0d3SRoger A. Faulkner }
106*a7e1d0d3SRoger A. Faulkner 
107*a7e1d0d3SRoger A. Faulkner static const char *
108*a7e1d0d3SRoger A. Faulkner lookup_lofs_mount_point(const char *mountp)
109*a7e1d0d3SRoger A. Faulkner {
110*a7e1d0d3SRoger A. Faulkner 	struct lofs_mnttab *lmt;
111*a7e1d0d3SRoger A. Faulkner 
112*a7e1d0d3SRoger A. Faulkner 	assert(MUTEX_HELD(&lofs_lock));
113*a7e1d0d3SRoger A. Faulkner 
114*a7e1d0d3SRoger A. Faulkner 	for (lmt = lofs_mnttab; lmt != NULL; lmt = lmt->l_next) {
115*a7e1d0d3SRoger A. Faulkner 		if (strcmp(lmt->l_mountp, mountp) == 0)
116*a7e1d0d3SRoger A. Faulkner 			return (lmt->l_special);
117*a7e1d0d3SRoger A. Faulkner 	}
118*a7e1d0d3SRoger A. Faulkner 	return (NULL);
119*a7e1d0d3SRoger A. Faulkner }
120*a7e1d0d3SRoger A. Faulkner 
121186f7fbfSEdward Pilatowicz static path_node_t *
122186f7fbfSEdward Pilatowicz pn_push(path_node_t **pnp, char *path)
123186f7fbfSEdward Pilatowicz {
124186f7fbfSEdward Pilatowicz 	path_node_t *pn;
125186f7fbfSEdward Pilatowicz 
126186f7fbfSEdward Pilatowicz 	if ((pn = calloc(sizeof (path_node_t), 1)) == NULL)
127186f7fbfSEdward Pilatowicz 		return (NULL);
128186f7fbfSEdward Pilatowicz 
129186f7fbfSEdward Pilatowicz 	if ((pn->pn_path = strdup(path)) == NULL) {
130186f7fbfSEdward Pilatowicz 		free(pn);
131186f7fbfSEdward Pilatowicz 		return (NULL);
132186f7fbfSEdward Pilatowicz 	}
133186f7fbfSEdward Pilatowicz 	pn->pn_next = *pnp;
134186f7fbfSEdward Pilatowicz 	return (*pnp = pn);
135186f7fbfSEdward Pilatowicz }
136186f7fbfSEdward Pilatowicz 
137186f7fbfSEdward Pilatowicz static void
138186f7fbfSEdward Pilatowicz pn_free(path_node_t **pnp)
139186f7fbfSEdward Pilatowicz {
140186f7fbfSEdward Pilatowicz 	path_node_t *pn;
141186f7fbfSEdward Pilatowicz 
142186f7fbfSEdward Pilatowicz 	while (*pnp != NULL) {
143186f7fbfSEdward Pilatowicz 		pn = *pnp;
144186f7fbfSEdward Pilatowicz 		*pnp = pn->pn_next;
145186f7fbfSEdward Pilatowicz 		free(pn->pn_path);
146186f7fbfSEdward Pilatowicz 		free(pn);
147186f7fbfSEdward Pilatowicz 	}
148186f7fbfSEdward Pilatowicz }
149186f7fbfSEdward Pilatowicz 
150186f7fbfSEdward Pilatowicz static void
151186f7fbfSEdward Pilatowicz pn_free2(path_node_t **pn1, path_node_t **pn2)
152186f7fbfSEdward Pilatowicz {
153186f7fbfSEdward Pilatowicz 	pn_free(pn1);
154186f7fbfSEdward Pilatowicz 	pn_free(pn2);
155186f7fbfSEdward Pilatowicz }
156186f7fbfSEdward Pilatowicz 
157186f7fbfSEdward Pilatowicz static char *
158186f7fbfSEdward Pilatowicz pn_pop(path_node_t **pnp, char *path)
159186f7fbfSEdward Pilatowicz {
160186f7fbfSEdward Pilatowicz 	path_node_t *pn;
161186f7fbfSEdward Pilatowicz 
162186f7fbfSEdward Pilatowicz 	if (*pnp == NULL)
163186f7fbfSEdward Pilatowicz 		return (NULL);
164186f7fbfSEdward Pilatowicz 
165186f7fbfSEdward Pilatowicz 	pn = *pnp;
166186f7fbfSEdward Pilatowicz 	*pnp = pn->pn_next;
167186f7fbfSEdward Pilatowicz 	pn->pn_next = NULL;
168186f7fbfSEdward Pilatowicz 
169186f7fbfSEdward Pilatowicz 	if (path == NULL) {
170186f7fbfSEdward Pilatowicz 		pn_free(&pn);
171186f7fbfSEdward Pilatowicz 		return (NULL);
172186f7fbfSEdward Pilatowicz 	}
173186f7fbfSEdward Pilatowicz 	(void) strlcpy(path, pn->pn_path, PATH_MAX);
174186f7fbfSEdward Pilatowicz 	pn_free(&pn);
175186f7fbfSEdward Pilatowicz 	return (path);
176186f7fbfSEdward Pilatowicz }
177186f7fbfSEdward Pilatowicz 
178186f7fbfSEdward Pilatowicz 
179186f7fbfSEdward Pilatowicz /*
180186f7fbfSEdward Pilatowicz  * Libzonecfg.so links against libproc, so libproc can't link against
181186f7fbfSEdward Pilatowicz  * libzonecfg.so.  Also, libzonecfg.so is optional and might not be
182186f7fbfSEdward Pilatowicz  * installed.  Hence instead of relying on linking to access libzonecfg.so,
183186f7fbfSEdward Pilatowicz  * we'll try dlopening it here.  This trick is borrowed from
184186f7fbfSEdward Pilatowicz  * libc`zone_get_id(), see that function for more detailed comments.
185186f7fbfSEdward Pilatowicz  */
186186f7fbfSEdward Pilatowicz static int
187186f7fbfSEdward Pilatowicz i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
188186f7fbfSEdward Pilatowicz {
189186f7fbfSEdward Pilatowicz 	typedef	int (*zone_get_zonepath_t)(char *, char *, size_t);
190186f7fbfSEdward Pilatowicz 	static zone_get_zonepath_t zone_get_zonepath_fp = NULL;
191186f7fbfSEdward Pilatowicz 
192186f7fbfSEdward Pilatowicz 	if (zone_get_zonepath_fp == NULL) {
193186f7fbfSEdward Pilatowicz 		/* There's no harm in doing this multiple times. */
194186f7fbfSEdward Pilatowicz 		void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY);
195186f7fbfSEdward Pilatowicz 		void *sym = (void *)(-1);
196186f7fbfSEdward Pilatowicz 		if (dlhandle != NULL &&
197186f7fbfSEdward Pilatowicz 		    (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) {
198186f7fbfSEdward Pilatowicz 			sym = (void *)(-1);
199186f7fbfSEdward Pilatowicz 			(void) dlclose(dlhandle);
200186f7fbfSEdward Pilatowicz 		}
201186f7fbfSEdward Pilatowicz 		zone_get_zonepath_fp = (zone_get_zonepath_t)sym;
202186f7fbfSEdward Pilatowicz 	}
203186f7fbfSEdward Pilatowicz 
204186f7fbfSEdward Pilatowicz 	/* If we've successfully loaded it, call the real function */
205186f7fbfSEdward Pilatowicz 	if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1))
206186f7fbfSEdward Pilatowicz 		return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz));
207186f7fbfSEdward Pilatowicz 	return (Z_NO_ZONE);
208186f7fbfSEdward Pilatowicz }
209186f7fbfSEdward Pilatowicz 
210186f7fbfSEdward Pilatowicz char *
211186f7fbfSEdward Pilatowicz Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen)
212186f7fbfSEdward Pilatowicz {
213186f7fbfSEdward Pilatowicz 	long	addr;
214186f7fbfSEdward Pilatowicz 
215186f7fbfSEdward Pilatowicz 	if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1)
216186f7fbfSEdward Pilatowicz 		return (NULL);
217186f7fbfSEdward Pilatowicz 
218186f7fbfSEdward Pilatowicz 	if (Pread_string(P, buf, buflen, addr) == -1)
219186f7fbfSEdward Pilatowicz 		return (NULL);
220186f7fbfSEdward Pilatowicz 
221186f7fbfSEdward Pilatowicz 	return (buf);
222186f7fbfSEdward Pilatowicz }
223186f7fbfSEdward Pilatowicz 
224186f7fbfSEdward Pilatowicz /*
225186f7fbfSEdward Pilatowicz  * Get the zone name from the core file if we have it; look up the
226186f7fbfSEdward Pilatowicz  * name based on the zone id if this is a live process.
227186f7fbfSEdward Pilatowicz  */
228186f7fbfSEdward Pilatowicz char *
229186f7fbfSEdward Pilatowicz Pzonename(struct ps_prochandle *P, char *s, size_t n)
230186f7fbfSEdward Pilatowicz {
231186f7fbfSEdward Pilatowicz 	if (P->state == PS_IDLE) {
232186f7fbfSEdward Pilatowicz 		errno = ENODATA;
233186f7fbfSEdward Pilatowicz 		return (NULL);
234186f7fbfSEdward Pilatowicz 	}
235186f7fbfSEdward Pilatowicz 
236186f7fbfSEdward Pilatowicz 	if (P->state == PS_DEAD) {
237186f7fbfSEdward Pilatowicz 		if (P->core->core_zonename == NULL) {
238186f7fbfSEdward Pilatowicz 			errno = ENODATA;
239186f7fbfSEdward Pilatowicz 			return (NULL);
240186f7fbfSEdward Pilatowicz 		}
241186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, P->core->core_zonename, n);
242186f7fbfSEdward Pilatowicz 	} else {
243186f7fbfSEdward Pilatowicz 		if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
244186f7fbfSEdward Pilatowicz 			return (NULL);
245186f7fbfSEdward Pilatowicz 		s[n - 1] = '\0';
246186f7fbfSEdward Pilatowicz 	}
247186f7fbfSEdward Pilatowicz 	return (s);
248186f7fbfSEdward Pilatowicz }
249186f7fbfSEdward Pilatowicz 
250186f7fbfSEdward Pilatowicz char *
251186f7fbfSEdward Pilatowicz Pzoneroot(struct ps_prochandle *P, char *s, size_t n)
252186f7fbfSEdward Pilatowicz {
253186f7fbfSEdward Pilatowicz 	char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX];
254186f7fbfSEdward Pilatowicz 	int rv;
255186f7fbfSEdward Pilatowicz 
256186f7fbfSEdward Pilatowicz 	if (P->zoneroot != NULL) {
257186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, P->zoneroot, n);
258186f7fbfSEdward Pilatowicz 		return (s);
259186f7fbfSEdward Pilatowicz 	}
260186f7fbfSEdward Pilatowicz 
261186f7fbfSEdward Pilatowicz 	if ((Pzonename(P, zname, sizeof (zname)) == NULL) ||
262186f7fbfSEdward Pilatowicz 	    (strcmp(zname, GLOBAL_ZONENAME) == 0)) {
263186f7fbfSEdward Pilatowicz 		if ((P->zoneroot = strdup("")) == NULL) {
264186f7fbfSEdward Pilatowicz 			errno = ENOMEM;
265186f7fbfSEdward Pilatowicz 			return (NULL);
266186f7fbfSEdward Pilatowicz 		}
267186f7fbfSEdward Pilatowicz 		dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME);
268186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, P->zoneroot, n);
269186f7fbfSEdward Pilatowicz 		return (s);
270186f7fbfSEdward Pilatowicz 	}
271186f7fbfSEdward Pilatowicz 
272186f7fbfSEdward Pilatowicz 	if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) {
273186f7fbfSEdward Pilatowicz 		if ((P->zoneroot = strdup("")) == NULL) {
274186f7fbfSEdward Pilatowicz 			errno = ENOMEM;
275186f7fbfSEdward Pilatowicz 			return (NULL);
276186f7fbfSEdward Pilatowicz 		}
277186f7fbfSEdward Pilatowicz 		dprintf(
278186f7fbfSEdward Pilatowicz 		    "Pzoneroot zone not found '%s', defaulting to '%s'\n",
279186f7fbfSEdward Pilatowicz 		    zname, GLOBAL_ZONENAME);
280186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, P->zoneroot, n);
281186f7fbfSEdward Pilatowicz 		return (s);
282186f7fbfSEdward Pilatowicz 	}
283186f7fbfSEdward Pilatowicz 	(void) strlcat(zpath, "/root", sizeof (zpath));
284186f7fbfSEdward Pilatowicz 
285186f7fbfSEdward Pilatowicz 	if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) {
286186f7fbfSEdward Pilatowicz 		if ((P->zoneroot = strdup("")) == NULL) {
287186f7fbfSEdward Pilatowicz 			errno = ENOMEM;
288186f7fbfSEdward Pilatowicz 			return (NULL);
289186f7fbfSEdward Pilatowicz 		}
290186f7fbfSEdward Pilatowicz 		dprintf(
291186f7fbfSEdward Pilatowicz 		    "Pzoneroot can't access '%s:%s', defaulting to '%s'\n",
292186f7fbfSEdward Pilatowicz 		    zname, zpath, GLOBAL_ZONENAME);
293186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, P->zoneroot, n);
294186f7fbfSEdward Pilatowicz 		return (s);
295186f7fbfSEdward Pilatowicz 	}
296186f7fbfSEdward Pilatowicz 	tmp[rv] = '\0';
297186f7fbfSEdward Pilatowicz 	(void) strlcpy(zpath, tmp, sizeof (zpath));
298186f7fbfSEdward Pilatowicz 
299186f7fbfSEdward Pilatowicz 	if ((P->zoneroot = strdup(zpath)) == NULL) {
300186f7fbfSEdward Pilatowicz 		errno = ENOMEM;
301186f7fbfSEdward Pilatowicz 		return (NULL);
302186f7fbfSEdward Pilatowicz 	}
303186f7fbfSEdward Pilatowicz 	dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath);
304186f7fbfSEdward Pilatowicz 	(void) strlcpy(s, P->zoneroot, n);
305186f7fbfSEdward Pilatowicz 	return (s);
306186f7fbfSEdward Pilatowicz }
307186f7fbfSEdward Pilatowicz 
308186f7fbfSEdward Pilatowicz /*
309186f7fbfSEdward Pilatowicz  * Plofspath() takes a path, "path",  and removes any lofs components from
310186f7fbfSEdward Pilatowicz  * that path.  The resultant path (if different from the starting path)
311186f7fbfSEdward Pilatowicz  * is placed in "s", which is limited to "n" characters, and the return
312186f7fbfSEdward Pilatowicz  * value is the pointer s.  If there are no lofs components in the path
313186f7fbfSEdward Pilatowicz  * the NULL is returned and s is not modified.  It's ok for "path" and
314186f7fbfSEdward Pilatowicz  * "s" to be the same pointer.  (ie, the results can be stored directly
315186f7fbfSEdward Pilatowicz  * in the input buffer.)  The path that is passed in must be an absolute
316186f7fbfSEdward Pilatowicz  * path.
317186f7fbfSEdward Pilatowicz  *
318186f7fbfSEdward Pilatowicz  * Example:
319186f7fbfSEdward Pilatowicz  *	if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/"
320186f7fbfSEdward Pilatowicz  *	then "/candy/bar/" will be written into "s" and "s" will be returned.
321186f7fbfSEdward Pilatowicz  */
322186f7fbfSEdward Pilatowicz char *
323186f7fbfSEdward Pilatowicz Plofspath(const char *path, char *s, size_t n)
324186f7fbfSEdward Pilatowicz {
325186f7fbfSEdward Pilatowicz 	char tmp[PATH_MAX + 1];
326*a7e1d0d3SRoger A. Faulkner 	struct stat64 statb;
327*a7e1d0d3SRoger A. Faulkner 	const char *special;
328186f7fbfSEdward Pilatowicz 	char *p, *p2;
329186f7fbfSEdward Pilatowicz 	int rv;
330186f7fbfSEdward Pilatowicz 
331186f7fbfSEdward Pilatowicz 	dprintf("Plofspath path '%s'\n", path);
332186f7fbfSEdward Pilatowicz 
333186f7fbfSEdward Pilatowicz 	/* We only deal with absolute paths */
334186f7fbfSEdward Pilatowicz 	if (path[0] != '/')
335186f7fbfSEdward Pilatowicz 		return (NULL);
336186f7fbfSEdward Pilatowicz 
337186f7fbfSEdward Pilatowicz 	/* Make a copy of the path so that we can muck with it */
338186f7fbfSEdward Pilatowicz 	(void) strlcpy(tmp, path, sizeof (tmp) - 1);
339186f7fbfSEdward Pilatowicz 
340186f7fbfSEdward Pilatowicz 	/*
341186f7fbfSEdward Pilatowicz 	 * Use resolvepath() to make sure there are no consecutive or
342186f7fbfSEdward Pilatowicz 	 * trailing '/'s in the path.
343186f7fbfSEdward Pilatowicz 	 */
344186f7fbfSEdward Pilatowicz 	if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
345186f7fbfSEdward Pilatowicz 		tmp[rv] = '\0';
346186f7fbfSEdward Pilatowicz 
347*a7e1d0d3SRoger A. Faulkner 	(void) mutex_lock(&lofs_lock);
348*a7e1d0d3SRoger A. Faulkner 
349*a7e1d0d3SRoger A. Faulkner 	/*
350*a7e1d0d3SRoger A. Faulkner 	 * If /etc/mnttab has been modified since the last time
351*a7e1d0d3SRoger A. Faulkner 	 * we looked, then rebuild the lofs lookup cache.
352*a7e1d0d3SRoger A. Faulkner 	 */
353*a7e1d0d3SRoger A. Faulkner 	if (stat64(MNTTAB, &statb) == 0 &&
354*a7e1d0d3SRoger A. Faulkner 	    (statb.st_mtim.tv_sec != lofs_mstat.st_mtim.tv_sec ||
355*a7e1d0d3SRoger A. Faulkner 	    statb.st_mtim.tv_nsec != lofs_mstat.st_mtim.tv_nsec ||
356*a7e1d0d3SRoger A. Faulkner 	    statb.st_ctim.tv_sec != lofs_mstat.st_ctim.tv_sec ||
357*a7e1d0d3SRoger A. Faulkner 	    statb.st_ctim.tv_nsec != lofs_mstat.st_ctim.tv_nsec)) {
358*a7e1d0d3SRoger A. Faulkner 		lofs_mstat = statb;
359*a7e1d0d3SRoger A. Faulkner 		rebuild_lofs_cache();
360*a7e1d0d3SRoger A. Faulkner 	}
361*a7e1d0d3SRoger A. Faulkner 
362186f7fbfSEdward Pilatowicz 	/*
363186f7fbfSEdward Pilatowicz 	 * So now we're going to search the path for any components that
364186f7fbfSEdward Pilatowicz 	 * might be lofs mounts.  We'll start out search from the full
365186f7fbfSEdward Pilatowicz 	 * path and then step back through each parent directly till
366186f7fbfSEdward Pilatowicz 	 * we reach the root.  If we find a lofs mount point in the path
367186f7fbfSEdward Pilatowicz 	 * then we'll replace the initial portion of the path (up
368186f7fbfSEdward Pilatowicz 	 * to that mount point) with the source of that mount point
369186f7fbfSEdward Pilatowicz 	 * and then start our search over again.
370186f7fbfSEdward Pilatowicz 	 *
371186f7fbfSEdward Pilatowicz 	 * Here's some of the variables we're going to use:
372186f7fbfSEdward Pilatowicz 	 *
373186f7fbfSEdward Pilatowicz 	 *	tmp - A pointer to our working copy of the path.  Sometimes
374186f7fbfSEdward Pilatowicz 	 *		this path will be divided into two strings by a
375186f7fbfSEdward Pilatowicz 	 *		'\0' (NUL) character.  The first string is the
376186f7fbfSEdward Pilatowicz 	 *		component we're currently checking and the second
377186f7fbfSEdward Pilatowicz 	 *		string is the path components we've already checked.
378186f7fbfSEdward Pilatowicz 	 *
379186f7fbfSEdward Pilatowicz 	 *	p - A pointer to the last '/' seen in the string.
380186f7fbfSEdward Pilatowicz 	 *
381186f7fbfSEdward Pilatowicz 	 *	p[1] - A pointer to the component of the string we've already
382186f7fbfSEdward Pilatowicz 	 *		checked.
383186f7fbfSEdward Pilatowicz 	 *
384186f7fbfSEdward Pilatowicz 	 * Initially, p will point to the end of our path and p[1] will point
385186f7fbfSEdward Pilatowicz 	 * to an extra '\0' (NUL) that we'll append to the end of the string.
386186f7fbfSEdward Pilatowicz 	 * (This is why we declared tmp with a size of PATH_MAX + 1).
387186f7fbfSEdward Pilatowicz 	 */
388186f7fbfSEdward Pilatowicz 	p = &tmp[strlen(tmp)];
389186f7fbfSEdward Pilatowicz 	p[1] = '\0';
390186f7fbfSEdward Pilatowicz 	for (;;) {
391*a7e1d0d3SRoger A. Faulkner 		if ((special = lookup_lofs_mount_point(tmp)) != NULL) {
392186f7fbfSEdward Pilatowicz 			char tmp2[PATH_MAX + 1];
393186f7fbfSEdward Pilatowicz 
394186f7fbfSEdward Pilatowicz 			/*
395186f7fbfSEdward Pilatowicz 			 * We found a lofs mount.  Update the path that we're
396186f7fbfSEdward Pilatowicz 			 * checking and start over.  This means append the
397186f7fbfSEdward Pilatowicz 			 * portion of the path we've already checked to the
398186f7fbfSEdward Pilatowicz 			 * source of the lofs mount and re-start this entire
399186f7fbfSEdward Pilatowicz 			 * lofs resolution loop.  Use resolvepath() to make
400186f7fbfSEdward Pilatowicz 			 * sure there are no consecutive or trailing '/'s
401186f7fbfSEdward Pilatowicz 			 * in the path.
402186f7fbfSEdward Pilatowicz 			 */
403*a7e1d0d3SRoger A. Faulkner 			(void) strlcpy(tmp2, special, sizeof (tmp2) - 1);
404186f7fbfSEdward Pilatowicz 			(void) strlcat(tmp2, "/", sizeof (tmp2) - 1);
405186f7fbfSEdward Pilatowicz 			(void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1);
406186f7fbfSEdward Pilatowicz 			(void) strlcpy(tmp, tmp2, sizeof (tmp) - 1);
407186f7fbfSEdward Pilatowicz 			if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
408186f7fbfSEdward Pilatowicz 				tmp[rv] = '\0';
409186f7fbfSEdward Pilatowicz 			p = &tmp[strlen(tmp)];
410186f7fbfSEdward Pilatowicz 			p[1] = '\0';
411186f7fbfSEdward Pilatowicz 			continue;
412186f7fbfSEdward Pilatowicz 		}
413186f7fbfSEdward Pilatowicz 
414186f7fbfSEdward Pilatowicz 		/* No lofs mount found */
415186f7fbfSEdward Pilatowicz 		if ((p2 = strrchr(tmp, '/')) == NULL) {
416186f7fbfSEdward Pilatowicz 			char tmp2[PATH_MAX];
417186f7fbfSEdward Pilatowicz 
418*a7e1d0d3SRoger A. Faulkner 			(void) mutex_unlock(&lofs_lock);
419*a7e1d0d3SRoger A. Faulkner 
420186f7fbfSEdward Pilatowicz 			/*
421186f7fbfSEdward Pilatowicz 			 * We know that tmp was an absolute path, so if we
422186f7fbfSEdward Pilatowicz 			 * made it here we know that (p == tmp) and that
423186f7fbfSEdward Pilatowicz 			 * (*p == '\0').  This means that we've managed
424186f7fbfSEdward Pilatowicz 			 * to check the whole path and so we're done.
425186f7fbfSEdward Pilatowicz 			 */
426186f7fbfSEdward Pilatowicz 			assert(p == tmp);
427186f7fbfSEdward Pilatowicz 			assert(p[0] == '\0');
428186f7fbfSEdward Pilatowicz 
429186f7fbfSEdward Pilatowicz 			/* Restore the leading '/' in the path */
430186f7fbfSEdward Pilatowicz 			p[0] = '/';
431186f7fbfSEdward Pilatowicz 
432186f7fbfSEdward Pilatowicz 			if (strcmp(tmp, path) == 0) {
433186f7fbfSEdward Pilatowicz 				/* The path didn't change */
434186f7fbfSEdward Pilatowicz 				return (NULL);
435186f7fbfSEdward Pilatowicz 			}
436186f7fbfSEdward Pilatowicz 
437186f7fbfSEdward Pilatowicz 			/*
438186f7fbfSEdward Pilatowicz 			 * It's possible that lofs source path we just
439186f7fbfSEdward Pilatowicz 			 * obtained contains a symbolic link.  Use
440186f7fbfSEdward Pilatowicz 			 * resolvepath() to clean it up.
441186f7fbfSEdward Pilatowicz 			 */
442186f7fbfSEdward Pilatowicz 			(void) strlcpy(tmp2, tmp, sizeof (tmp2));
443186f7fbfSEdward Pilatowicz 			if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
444186f7fbfSEdward Pilatowicz 				tmp[rv] = '\0';
445186f7fbfSEdward Pilatowicz 
446186f7fbfSEdward Pilatowicz 			/*
447186f7fbfSEdward Pilatowicz 			 * It's always possible that our lofs source path is
448186f7fbfSEdward Pilatowicz 			 * actually another lofs mount.  So call ourselves
449186f7fbfSEdward Pilatowicz 			 * recursively to resolve that path.
450186f7fbfSEdward Pilatowicz 			 */
451186f7fbfSEdward Pilatowicz 			(void) Plofspath(tmp, tmp, PATH_MAX);
452186f7fbfSEdward Pilatowicz 
453186f7fbfSEdward Pilatowicz 			/* Copy out our final resolved lofs source path */
454186f7fbfSEdward Pilatowicz 			(void) strlcpy(s, tmp, n);
455186f7fbfSEdward Pilatowicz 			dprintf("Plofspath path result '%s'\n", s);
456186f7fbfSEdward Pilatowicz 			return (s);
457186f7fbfSEdward Pilatowicz 		}
458186f7fbfSEdward Pilatowicz 
459186f7fbfSEdward Pilatowicz 		/*
460186f7fbfSEdward Pilatowicz 		 * So the path we just checked is not a lofs mount.  Next we
461186f7fbfSEdward Pilatowicz 		 * want to check the parent path component for a lofs mount.
462186f7fbfSEdward Pilatowicz 		 *
463186f7fbfSEdward Pilatowicz 		 * First, restore any '/' that we replaced with a '\0' (NUL).
464186f7fbfSEdward Pilatowicz 		 * We can determine if we should do this by looking at p[1].
465186f7fbfSEdward Pilatowicz 		 * If p[1] points to a '\0' (NUL) then we know that p points
466186f7fbfSEdward Pilatowicz 		 * to the end of the string and there is no '/' to restore.
467186f7fbfSEdward Pilatowicz 		 * if p[1] doesn't point to a '\0' (NUL) then it points to
468186f7fbfSEdward Pilatowicz 		 * the part of the path that we've already verified so there
469186f7fbfSEdward Pilatowicz 		 * is a '/' to restore.
470186f7fbfSEdward Pilatowicz 		 */
471186f7fbfSEdward Pilatowicz 		if (p[1] != '\0')
472186f7fbfSEdward Pilatowicz 			p[0] = '/';
473186f7fbfSEdward Pilatowicz 
474186f7fbfSEdward Pilatowicz 		/*
475186f7fbfSEdward Pilatowicz 		 * Second, replace the last '/' in the part of the path
476186f7fbfSEdward Pilatowicz 		 * that we've already checked with a '\0' (NUL) so that
477186f7fbfSEdward Pilatowicz 		 * when we loop around we check the parent component of the
478186f7fbfSEdward Pilatowicz 		 * path.
479186f7fbfSEdward Pilatowicz 		 */
480186f7fbfSEdward Pilatowicz 		p2[0] = '\0';
481186f7fbfSEdward Pilatowicz 		p = p2;
482186f7fbfSEdward Pilatowicz 	}
483186f7fbfSEdward Pilatowicz 	/*NOTREACHED*/
484186f7fbfSEdward Pilatowicz }
485186f7fbfSEdward Pilatowicz 
486186f7fbfSEdward Pilatowicz /*
487186f7fbfSEdward Pilatowicz  * Pzonepath() - Way too much code to attempt to derive the full path of
488186f7fbfSEdward Pilatowicz  * an object within a zone.
489186f7fbfSEdward Pilatowicz  *
490186f7fbfSEdward Pilatowicz  * Pzonepath() takes a path and attempts to resolve it relative to the
491186f7fbfSEdward Pilatowicz  * root associated with the current process handle.  If it fails it will
492186f7fbfSEdward Pilatowicz  * not update the results string.  It is safe to specify the same pointer
493186f7fbfSEdward Pilatowicz  * for the file string and the results string.
494186f7fbfSEdward Pilatowicz  *
495186f7fbfSEdward Pilatowicz  * Doing this resolution is more difficult than it initially sounds.
496186f7fbfSEdward Pilatowicz  * We can't simply append the file path to the zone root, because in
497186f7fbfSEdward Pilatowicz  * a root directory, '..' is treated the same as '.'.  Also, symbolic
498186f7fbfSEdward Pilatowicz  * links that specify an absolute path need to be interpreted relative
499186f7fbfSEdward Pilatowicz  * to the zone root.
500186f7fbfSEdward Pilatowicz  *
501186f7fbfSEdward Pilatowicz  * It seems like perhaps we could do a chroot(<zone root>) followed by a
502186f7fbfSEdward Pilatowicz  * resolvepath().  But we can't do this because chroot requires special
503186f7fbfSEdward Pilatowicz  * privileges and affects the entire process.  Perhaps if there was a
504186f7fbfSEdward Pilatowicz  * special version of resolvepath() which took an addition root path
505186f7fbfSEdward Pilatowicz  * we could use that, but this isn't ideal either.  The reason is
506186f7fbfSEdward Pilatowicz  * that we want to have special handling for native paths.  (A native path
507186f7fbfSEdward Pilatowicz  * is a path that begins with "/native/" or "/.SUNWnative/".)  Native
508186f7fbfSEdward Pilatowicz  * paths could be passed explicity to this function or could be embedded
509186f7fbfSEdward Pilatowicz  * in a symlink that is part of the path passed into this function.
510186f7fbfSEdward Pilatowicz  * These paths are always lofs mounts of global zone paths, but lofs
511186f7fbfSEdward Pilatowicz  * mounts only exist when a zone is booted.  So if we were to try to do
512186f7fbfSEdward Pilatowicz  * a resolvepath() on a native path when the zone wasn't booted the
513186f7fbfSEdward Pilatowicz  * resolvepath() would fail even though we know that the components
514186f7fbfSEdward Pilatowicz  * exists in the global zone.
515186f7fbfSEdward Pilatowicz  *
516186f7fbfSEdward Pilatowicz  * Given all these constraints, we just implement a path walking function
517186f7fbfSEdward Pilatowicz  * that resolves a file path relative to a zone root by manually inspecting
518186f7fbfSEdward Pilatowicz  * each of the path components and verifying its existence.  This means that
519186f7fbfSEdward Pilatowicz  * we must have access to the zone and that all the components of the
520186f7fbfSEdward Pilatowicz  * path must exist for this operation to succeed.
521186f7fbfSEdward Pilatowicz  */
522186f7fbfSEdward Pilatowicz char *
523186f7fbfSEdward Pilatowicz Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n)
524186f7fbfSEdward Pilatowicz {
525186f7fbfSEdward Pilatowicz 	char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX];
526186f7fbfSEdward Pilatowicz 	path_node_t *pn_stack = NULL, *pn_links = NULL, *pn;
527186f7fbfSEdward Pilatowicz 	struct stat64 sb;
528186f7fbfSEdward Pilatowicz 	char *p;
529186f7fbfSEdward Pilatowicz 	int i, rv;
530186f7fbfSEdward Pilatowicz 
531186f7fbfSEdward Pilatowicz 	dprintf("Pzonepath lookup '%s'\n", path);
532186f7fbfSEdward Pilatowicz 
533186f7fbfSEdward Pilatowicz 	/* First lookup the zone root */
534186f7fbfSEdward Pilatowicz 	if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL)
535186f7fbfSEdward Pilatowicz 		return (NULL);
536186f7fbfSEdward Pilatowicz 
537186f7fbfSEdward Pilatowicz 	/*
538186f7fbfSEdward Pilatowicz 	 * Make a temporary copy of the path specified.
539186f7fbfSEdward Pilatowicz 	 * If it's a relative path then make it into an absolute path.
540186f7fbfSEdward Pilatowicz 	 */
541186f7fbfSEdward Pilatowicz 	tmp[0] = '\0';
542186f7fbfSEdward Pilatowicz 	if (path[0] != '/')
543186f7fbfSEdward Pilatowicz 		(void) strlcat(tmp, "/", sizeof (tmp));
544186f7fbfSEdward Pilatowicz 	(void) strlcat(tmp, path, sizeof (tmp));
545186f7fbfSEdward Pilatowicz 
546186f7fbfSEdward Pilatowicz 	/*
547186f7fbfSEdward Pilatowicz 	 * If the path that was passed in is the zone root, we're done.
548186f7fbfSEdward Pilatowicz 	 * If the path that was passed in already contains the zone root
549186f7fbfSEdward Pilatowicz 	 * then strip the zone root out and verify the rest of the path.
550186f7fbfSEdward Pilatowicz 	 */
551186f7fbfSEdward Pilatowicz 	if (strcmp(tmp, zroot) == 0) {
552186f7fbfSEdward Pilatowicz 		(void) Plofspath(zroot, zroot, sizeof (zroot));
553186f7fbfSEdward Pilatowicz 		dprintf("Pzonepath found zone path (1) '%s'\n", zroot);
554186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, zroot, n);
555186f7fbfSEdward Pilatowicz 		return (s);
556186f7fbfSEdward Pilatowicz 	}
557186f7fbfSEdward Pilatowicz 	i = strlen(zroot);
558186f7fbfSEdward Pilatowicz 	if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/'))
559186f7fbfSEdward Pilatowicz 		(void) memmove(tmp, tmp + i, strlen(tmp + i) + 1);
560186f7fbfSEdward Pilatowicz 
561186f7fbfSEdward Pilatowicz 	/* If no path is passed in, then it maps to the zone root */
562186f7fbfSEdward Pilatowicz 	if (strlen(tmp) == 0) {
563186f7fbfSEdward Pilatowicz 		(void) Plofspath(zroot, zroot, sizeof (zroot));
564186f7fbfSEdward Pilatowicz 		dprintf("Pzonepath found zone path (2) '%s'\n", zroot);
565186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, zroot, n);
566186f7fbfSEdward Pilatowicz 		return (s);
567186f7fbfSEdward Pilatowicz 	}
568186f7fbfSEdward Pilatowicz 
569186f7fbfSEdward Pilatowicz 	/*
570186f7fbfSEdward Pilatowicz 	 * Push each path component that we plan to verify onto a stack of
571186f7fbfSEdward Pilatowicz 	 * path components, with parent components at the top of the stack.
572186f7fbfSEdward Pilatowicz 	 * So for example, if we're going to verify the path /foo/bar/bang
573186f7fbfSEdward Pilatowicz 	 * then our stack will look like:
574186f7fbfSEdward Pilatowicz 	 *	foo	(top)
575186f7fbfSEdward Pilatowicz 	 *	bar
576186f7fbfSEdward Pilatowicz 	 *	bang	(bottom)
577186f7fbfSEdward Pilatowicz 	 */
578186f7fbfSEdward Pilatowicz 	while ((p = strrchr(tmp, '/')) != NULL) {
579186f7fbfSEdward Pilatowicz 		*p = '\0';
580186f7fbfSEdward Pilatowicz 		if (pn_push(&pn_stack, &p[1]) != NULL)
581186f7fbfSEdward Pilatowicz 			continue;
582186f7fbfSEdward Pilatowicz 		pn_free(&pn_stack);
583186f7fbfSEdward Pilatowicz 		return (NULL);
584186f7fbfSEdward Pilatowicz 	}
585186f7fbfSEdward Pilatowicz 
586186f7fbfSEdward Pilatowicz 	/* We're going to store the final zone relative path in zpath */
587186f7fbfSEdward Pilatowicz 	*zpath = '\0';
588186f7fbfSEdward Pilatowicz 
589186f7fbfSEdward Pilatowicz 	while (pn_pop(&pn_stack, tmp) != NULL) {
590186f7fbfSEdward Pilatowicz 		/*
591186f7fbfSEdward Pilatowicz 		 * Drop zero length path components (which come from
592186f7fbfSEdward Pilatowicz 		 * consecutive '/'s) and '.' path components.
593186f7fbfSEdward Pilatowicz 		 */
594186f7fbfSEdward Pilatowicz 		if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0))
595186f7fbfSEdward Pilatowicz 			continue;
596186f7fbfSEdward Pilatowicz 
597186f7fbfSEdward Pilatowicz 		/*
598186f7fbfSEdward Pilatowicz 		 * Check the current path component for '..', if found
599186f7fbfSEdward Pilatowicz 		 * drop any previous path component.
600186f7fbfSEdward Pilatowicz 		 */
601186f7fbfSEdward Pilatowicz 		if (strcmp(tmp, "..") == 0) {
602186f7fbfSEdward Pilatowicz 			if ((p = strrchr(zpath, '/')) != NULL)
603186f7fbfSEdward Pilatowicz 				*p = '\0';
604186f7fbfSEdward Pilatowicz 			continue;
605186f7fbfSEdward Pilatowicz 		}
606186f7fbfSEdward Pilatowicz 
607186f7fbfSEdward Pilatowicz 		/* The path we want to verify now is zpath + / + tmp. */
608186f7fbfSEdward Pilatowicz 		(void) strlcat(zpath, "/", sizeof (zpath));
609186f7fbfSEdward Pilatowicz 		(void) strlcat(zpath, tmp, sizeof (zpath));
610186f7fbfSEdward Pilatowicz 
611186f7fbfSEdward Pilatowicz 		/*
612186f7fbfSEdward Pilatowicz 		 * Check if this is a native object.  A native object is an
613186f7fbfSEdward Pilatowicz 		 * object from the global zone that is running in a branded
614186f7fbfSEdward Pilatowicz 		 * zone.  These objects are lofs mounted into a zone.  So if a
615186f7fbfSEdward Pilatowicz 		 * branded zone is not booted then lofs mounts won't be setup
616186f7fbfSEdward Pilatowicz 		 * so we won't be able to find these objects.  Luckily, we know
617186f7fbfSEdward Pilatowicz 		 * that they exist in the global zone with the same path sans
618186f7fbfSEdward Pilatowicz 		 * the initial native component, so we'll just strip out the
619186f7fbfSEdward Pilatowicz 		 * native component here.
620186f7fbfSEdward Pilatowicz 		 */
621186f7fbfSEdward Pilatowicz 		if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) ||
622186f7fbfSEdward Pilatowicz 		    (strncmp(zpath, "/.SUNWnative",
623186f7fbfSEdward Pilatowicz 		    sizeof ("/.SUNWnative")) == 0)) {
624186f7fbfSEdward Pilatowicz 
625186f7fbfSEdward Pilatowicz 			/* Free any cached symlink paths */
626186f7fbfSEdward Pilatowicz 			pn_free(&pn_links);
627186f7fbfSEdward Pilatowicz 
628186f7fbfSEdward Pilatowicz 			/* Reconstruct the path from our path component stack */
629186f7fbfSEdward Pilatowicz 			*zpath = '\0';
630186f7fbfSEdward Pilatowicz 			while (pn_pop(&pn_stack, tmp) != NULL) {
631186f7fbfSEdward Pilatowicz 				(void) strlcat(zpath, "/", sizeof (zpath));
632186f7fbfSEdward Pilatowicz 				(void) strlcat(zpath, tmp, sizeof (zpath));
633186f7fbfSEdward Pilatowicz 			}
634186f7fbfSEdward Pilatowicz 
635186f7fbfSEdward Pilatowicz 			/* Verify that the path actually exists */
636186f7fbfSEdward Pilatowicz 			rv = resolvepath(zpath, tmp, sizeof (tmp) - 1);
637186f7fbfSEdward Pilatowicz 			if (rv < 0) {
638186f7fbfSEdward Pilatowicz 				dprintf("Pzonepath invalid native path '%s'\n",
639186f7fbfSEdward Pilatowicz 				    zpath);
640186f7fbfSEdward Pilatowicz 				return (NULL);
641186f7fbfSEdward Pilatowicz 			}
642186f7fbfSEdward Pilatowicz 			tmp[rv] = '\0';
643186f7fbfSEdward Pilatowicz 
644186f7fbfSEdward Pilatowicz 			/* Return the path */
645186f7fbfSEdward Pilatowicz 			dprintf("Pzonepath found native path '%s'\n", tmp);
646186f7fbfSEdward Pilatowicz 			(void) Plofspath(tmp, tmp, sizeof (tmp));
647186f7fbfSEdward Pilatowicz 			(void) strlcpy(s, tmp, n);
648186f7fbfSEdward Pilatowicz 			return (s);
649186f7fbfSEdward Pilatowicz 		}
650186f7fbfSEdward Pilatowicz 
651186f7fbfSEdward Pilatowicz 		/*
652186f7fbfSEdward Pilatowicz 		 * Check if the path points to a symlink.  We do this
653186f7fbfSEdward Pilatowicz 		 * explicitly since any absolute symlink needs to be
654186f7fbfSEdward Pilatowicz 		 * interpreted relativly to the zone root and not "/".
655186f7fbfSEdward Pilatowicz 		 */
656186f7fbfSEdward Pilatowicz 		(void) strlcpy(tmp, zroot, sizeof (tmp));
657186f7fbfSEdward Pilatowicz 		(void) strlcat(tmp, zpath, sizeof (tmp));
658186f7fbfSEdward Pilatowicz 		if (lstat64(tmp, &sb) != 0) {
659186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
660186f7fbfSEdward Pilatowicz 			return (NULL);
661186f7fbfSEdward Pilatowicz 		}
662186f7fbfSEdward Pilatowicz 		if (!S_ISLNK(sb.st_mode)) {
663186f7fbfSEdward Pilatowicz 			/*
664186f7fbfSEdward Pilatowicz 			 * Since the lstat64() above succeeded we know that
665186f7fbfSEdward Pilatowicz 			 * zpath exists, since this is not a symlink loop
666186f7fbfSEdward Pilatowicz 			 * around and check the next path component.
667186f7fbfSEdward Pilatowicz 			 */
668186f7fbfSEdward Pilatowicz 			continue;
669186f7fbfSEdward Pilatowicz 		}
670186f7fbfSEdward Pilatowicz 
671186f7fbfSEdward Pilatowicz 		/*
672186f7fbfSEdward Pilatowicz 		 * Symlink allow for paths with loops.  Make sure
673186f7fbfSEdward Pilatowicz 		 * we're not stuck in a loop.
674186f7fbfSEdward Pilatowicz 		 */
675186f7fbfSEdward Pilatowicz 		for (pn = pn_links; pn != NULL; pn = pn->pn_next) {
676186f7fbfSEdward Pilatowicz 			if (strcmp(zpath, pn->pn_path) != 0)
677186f7fbfSEdward Pilatowicz 				continue;
678186f7fbfSEdward Pilatowicz 
679186f7fbfSEdward Pilatowicz 			/* We have a loop.  Fail. */
680186f7fbfSEdward Pilatowicz 			dprintf("Pzonepath symlink loop '%s'\n", zpath);
681186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
682186f7fbfSEdward Pilatowicz 			return (NULL);
683186f7fbfSEdward Pilatowicz 		}
684186f7fbfSEdward Pilatowicz 
685186f7fbfSEdward Pilatowicz 		/* Save this symlink path for future loop checks */
686186f7fbfSEdward Pilatowicz 		if (pn_push(&pn_links, zpath) == NULL) {
687186f7fbfSEdward Pilatowicz 			/* Out of memory */
688186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
689186f7fbfSEdward Pilatowicz 			return (NULL);
690186f7fbfSEdward Pilatowicz 		}
691186f7fbfSEdward Pilatowicz 
692186f7fbfSEdward Pilatowicz 		/* Now follow the contents of the symlink */
693186f7fbfSEdward Pilatowicz 		bzero(link, sizeof (link));
694186f7fbfSEdward Pilatowicz 		if (readlink(tmp, link, sizeof (link)) == -1) {
695186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
696186f7fbfSEdward Pilatowicz 			return (NULL);
697186f7fbfSEdward Pilatowicz 		}
698186f7fbfSEdward Pilatowicz 
699186f7fbfSEdward Pilatowicz 		dprintf("Pzonepath following symlink '%s' -> '%s'\n",
700186f7fbfSEdward Pilatowicz 		    zpath, link);
701186f7fbfSEdward Pilatowicz 
702186f7fbfSEdward Pilatowicz 		/*
703186f7fbfSEdward Pilatowicz 		 * Push each path component of the symlink target onto our
704186f7fbfSEdward Pilatowicz 		 * path components stack since we need to verify each one.
705186f7fbfSEdward Pilatowicz 		 */
706186f7fbfSEdward Pilatowicz 		while ((p = strrchr(link, '/')) != NULL) {
707186f7fbfSEdward Pilatowicz 			*p = '\0';
708186f7fbfSEdward Pilatowicz 			if (pn_push(&pn_stack, &p[1]) != NULL)
709186f7fbfSEdward Pilatowicz 				continue;
710186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
711186f7fbfSEdward Pilatowicz 			return (NULL);
712186f7fbfSEdward Pilatowicz 		}
713186f7fbfSEdward Pilatowicz 
714186f7fbfSEdward Pilatowicz 		/* absolute or relative symlink? */
715186f7fbfSEdward Pilatowicz 		if (*link == '\0') {
716186f7fbfSEdward Pilatowicz 			/* Absolute symlink, nuke existing zpath. */
717186f7fbfSEdward Pilatowicz 			*zpath = '\0';
718186f7fbfSEdward Pilatowicz 			continue;
719186f7fbfSEdward Pilatowicz 		}
720186f7fbfSEdward Pilatowicz 
721186f7fbfSEdward Pilatowicz 		/*
722186f7fbfSEdward Pilatowicz 		 * Relative symlink.  Push the first path component of the
723186f7fbfSEdward Pilatowicz 		 * symlink target onto our stack for verification and then
724186f7fbfSEdward Pilatowicz 		 * remove the current path component from zpath.
725186f7fbfSEdward Pilatowicz 		 */
726186f7fbfSEdward Pilatowicz 		if (pn_push(&pn_stack, link) == NULL) {
727186f7fbfSEdward Pilatowicz 			pn_free2(&pn_stack, &pn_links);
728186f7fbfSEdward Pilatowicz 			return (NULL);
729186f7fbfSEdward Pilatowicz 		}
730186f7fbfSEdward Pilatowicz 		p = strrchr(zpath, '/');
731186f7fbfSEdward Pilatowicz 		assert(p != NULL);
732186f7fbfSEdward Pilatowicz 		*p = '\0';
733186f7fbfSEdward Pilatowicz 		continue;
734186f7fbfSEdward Pilatowicz 	}
735186f7fbfSEdward Pilatowicz 	pn_free(&pn_links);
736186f7fbfSEdward Pilatowicz 
737186f7fbfSEdward Pilatowicz 	/* Place the final result in zpath */
738186f7fbfSEdward Pilatowicz 	(void) strlcpy(tmp, zroot, sizeof (tmp));
739186f7fbfSEdward Pilatowicz 	(void) strlcat(tmp, zpath, sizeof (tmp));
740186f7fbfSEdward Pilatowicz 	(void) strlcpy(zpath, tmp, sizeof (zpath));
741186f7fbfSEdward Pilatowicz 
742186f7fbfSEdward Pilatowicz 	(void) Plofspath(zpath, zpath, sizeof (zpath));
743186f7fbfSEdward Pilatowicz 	dprintf("Pzonepath found zone path (3) '%s'\n", zpath);
744186f7fbfSEdward Pilatowicz 
745186f7fbfSEdward Pilatowicz 	(void) strlcpy(s, zpath, n);
746186f7fbfSEdward Pilatowicz 	return (s);
747186f7fbfSEdward Pilatowicz }
748186f7fbfSEdward Pilatowicz 
749186f7fbfSEdward Pilatowicz char *
750186f7fbfSEdward Pilatowicz Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n)
751186f7fbfSEdward Pilatowicz {
752186f7fbfSEdward Pilatowicz 	int len;
753186f7fbfSEdward Pilatowicz 
754186f7fbfSEdward Pilatowicz 	dprintf("Pfindobj '%s'\n", path);
755186f7fbfSEdward Pilatowicz 
756186f7fbfSEdward Pilatowicz 	/* We only deal with absolute paths */
757186f7fbfSEdward Pilatowicz 	if (path[0] != '/')
758186f7fbfSEdward Pilatowicz 		return (NULL);
759186f7fbfSEdward Pilatowicz 
760186f7fbfSEdward Pilatowicz 	/* First try to resolve the path to some zone */
761186f7fbfSEdward Pilatowicz 	if (Pzonepath(P, path, s, n) != NULL)
762186f7fbfSEdward Pilatowicz 		return (s);
763186f7fbfSEdward Pilatowicz 
764186f7fbfSEdward Pilatowicz 	/* If that fails resolve any lofs links in the path */
765186f7fbfSEdward Pilatowicz 	if (Plofspath(path, s, n) != NULL)
766186f7fbfSEdward Pilatowicz 		return (s);
767186f7fbfSEdward Pilatowicz 
768186f7fbfSEdward Pilatowicz 	/* If that fails then just see if the path exists */
769186f7fbfSEdward Pilatowicz 	if ((len = resolvepath(path, s, n)) > 0) {
770186f7fbfSEdward Pilatowicz 		s[len] = '\0';
771186f7fbfSEdward Pilatowicz 		return (s);
772186f7fbfSEdward Pilatowicz 	}
773186f7fbfSEdward Pilatowicz 
774186f7fbfSEdward Pilatowicz 	return (NULL);
775186f7fbfSEdward Pilatowicz }
776186f7fbfSEdward Pilatowicz 
777186f7fbfSEdward Pilatowicz char *
778186f7fbfSEdward Pilatowicz Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n)
779186f7fbfSEdward Pilatowicz {
780186f7fbfSEdward Pilatowicz 	file_info_t *fptr = mptr->map_file;
781186f7fbfSEdward Pilatowicz 	char buf[PATH_MAX];
782186f7fbfSEdward Pilatowicz 	int len;
783186f7fbfSEdward Pilatowicz 
784186f7fbfSEdward Pilatowicz 	/* If it's already been explicity set return that */
785186f7fbfSEdward Pilatowicz 	if ((fptr != NULL) && (fptr->file_rname != NULL)) {
786186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, fptr->file_rname, n);
787186f7fbfSEdward Pilatowicz 		return (s);
788186f7fbfSEdward Pilatowicz 	}
789186f7fbfSEdward Pilatowicz 
790186f7fbfSEdward Pilatowicz 	/* If it's the a.out segment, defer to the magical Pexecname() */
791186f7fbfSEdward Pilatowicz 	if ((P->map_exec == mptr) ||
792186f7fbfSEdward Pilatowicz 	    (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) ||
793186f7fbfSEdward Pilatowicz 	    ((fptr != NULL) && (fptr->file_lname != NULL) &&
794186f7fbfSEdward Pilatowicz 	    (strcmp(fptr->file_lname, "a.out") == 0))) {
795186f7fbfSEdward Pilatowicz 		(void) Pexecname(P, buf, sizeof (buf));
796186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, buf, n);
797186f7fbfSEdward Pilatowicz 		return (s);
798186f7fbfSEdward Pilatowicz 	}
799186f7fbfSEdward Pilatowicz 
800186f7fbfSEdward Pilatowicz 	/* Try /proc first to get the real object name */
801186f7fbfSEdward Pilatowicz 	if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) {
802186f7fbfSEdward Pilatowicz 		(void) snprintf(buf, sizeof (buf), "%s/%d/path/%s",
803186f7fbfSEdward Pilatowicz 		    procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname);
804186f7fbfSEdward Pilatowicz 		if ((len = readlink(buf, buf, sizeof (buf))) > 0) {
805186f7fbfSEdward Pilatowicz 			buf[len] = '\0';
806186f7fbfSEdward Pilatowicz 			(void) Plofspath(buf, buf, sizeof (buf));
807186f7fbfSEdward Pilatowicz 			(void) strlcpy(s, buf, n);
808186f7fbfSEdward Pilatowicz 			return (s);
809186f7fbfSEdward Pilatowicz 		}
810186f7fbfSEdward Pilatowicz 	}
811186f7fbfSEdward Pilatowicz 
812186f7fbfSEdward Pilatowicz 	/*
813186f7fbfSEdward Pilatowicz 	 * If we couldn't get the name from /proc, take the lname and
814186f7fbfSEdward Pilatowicz 	 * try to expand it on the current system to a real object path.
815186f7fbfSEdward Pilatowicz 	 */
816186f7fbfSEdward Pilatowicz 	fptr = mptr->map_file;
817186f7fbfSEdward Pilatowicz 	if ((fptr != NULL) && (fptr->file_lname != NULL)) {
818186f7fbfSEdward Pilatowicz 		(void) strlcpy(buf, fptr->file_lname, sizeof (buf));
819186f7fbfSEdward Pilatowicz 		if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL)
820186f7fbfSEdward Pilatowicz 			return (NULL);
821186f7fbfSEdward Pilatowicz 		(void) strlcpy(s, buf, n);
822186f7fbfSEdward Pilatowicz 		return (s);
823186f7fbfSEdward Pilatowicz 	}
824186f7fbfSEdward Pilatowicz 
825186f7fbfSEdward Pilatowicz 	return (NULL);
826186f7fbfSEdward Pilatowicz }
827