xref: /onnv-gate/usr/src/lib/libproc/common/Pzone.c (revision 9868:e4b0e8133536)
17675SEdward.Pilatowicz@Sun.COM /*
27675SEdward.Pilatowicz@Sun.COM  * CDDL HEADER START
37675SEdward.Pilatowicz@Sun.COM  *
47675SEdward.Pilatowicz@Sun.COM  * The contents of this file are subject to the terms of the
57675SEdward.Pilatowicz@Sun.COM  * Common Development and Distribution License (the "License").
67675SEdward.Pilatowicz@Sun.COM  * You may not use this file except in compliance with the License.
77675SEdward.Pilatowicz@Sun.COM  *
87675SEdward.Pilatowicz@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97675SEdward.Pilatowicz@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107675SEdward.Pilatowicz@Sun.COM  * See the License for the specific language governing permissions
117675SEdward.Pilatowicz@Sun.COM  * and limitations under the License.
127675SEdward.Pilatowicz@Sun.COM  *
137675SEdward.Pilatowicz@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147675SEdward.Pilatowicz@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157675SEdward.Pilatowicz@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167675SEdward.Pilatowicz@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177675SEdward.Pilatowicz@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187675SEdward.Pilatowicz@Sun.COM  *
197675SEdward.Pilatowicz@Sun.COM  * CDDL HEADER END
207675SEdward.Pilatowicz@Sun.COM  */
217675SEdward.Pilatowicz@Sun.COM 
227675SEdward.Pilatowicz@Sun.COM /*
23*9868SRoger.Faulkner@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247675SEdward.Pilatowicz@Sun.COM  * Use is subject to license terms.
257675SEdward.Pilatowicz@Sun.COM  */
267675SEdward.Pilatowicz@Sun.COM 
277675SEdward.Pilatowicz@Sun.COM #include <assert.h>
287675SEdward.Pilatowicz@Sun.COM #include <dlfcn.h>
297675SEdward.Pilatowicz@Sun.COM #include <errno.h>
307675SEdward.Pilatowicz@Sun.COM #include <libzonecfg.h>
317675SEdward.Pilatowicz@Sun.COM #include <link.h>
327675SEdward.Pilatowicz@Sun.COM #include <string.h>
337675SEdward.Pilatowicz@Sun.COM #include <strings.h>
347675SEdward.Pilatowicz@Sun.COM #include <sys/list.h>
357675SEdward.Pilatowicz@Sun.COM #include <sys/types.h>
367675SEdward.Pilatowicz@Sun.COM #include <sys/mkdev.h>
377675SEdward.Pilatowicz@Sun.COM #include <sys/mman.h>
387675SEdward.Pilatowicz@Sun.COM #include <sys/mnttab.h>
397675SEdward.Pilatowicz@Sun.COM 
407675SEdward.Pilatowicz@Sun.COM #include "Pcontrol.h"
417675SEdward.Pilatowicz@Sun.COM 
427675SEdward.Pilatowicz@Sun.COM struct path_node {
437675SEdward.Pilatowicz@Sun.COM 	struct path_node	*pn_next;
447675SEdward.Pilatowicz@Sun.COM 	char			*pn_path;
457675SEdward.Pilatowicz@Sun.COM };
467675SEdward.Pilatowicz@Sun.COM typedef struct path_node path_node_t;
477675SEdward.Pilatowicz@Sun.COM 
48*9868SRoger.Faulkner@Sun.COM /*
49*9868SRoger.Faulkner@Sun.COM  * Parameters of the lofs lookup cache.
50*9868SRoger.Faulkner@Sun.COM  */
51*9868SRoger.Faulkner@Sun.COM static struct stat64 lofs_mstat; /* last stat() of MNTTAB */
52*9868SRoger.Faulkner@Sun.COM static struct lofs_mnttab {	/* linked list of all lofs mount points */
53*9868SRoger.Faulkner@Sun.COM 	struct lofs_mnttab *l_next;
54*9868SRoger.Faulkner@Sun.COM 	char	*l_special;	/* extracted from MNTTAB */
55*9868SRoger.Faulkner@Sun.COM 	char	*l_mountp;	/* ditto */
56*9868SRoger.Faulkner@Sun.COM } *lofs_mnttab = NULL;
57*9868SRoger.Faulkner@Sun.COM static mutex_t lofs_lock = DEFAULTMUTEX;	/* protects the lofs cache */
58*9868SRoger.Faulkner@Sun.COM 
59*9868SRoger.Faulkner@Sun.COM static void
rebuild_lofs_cache(void)60*9868SRoger.Faulkner@Sun.COM rebuild_lofs_cache(void)
61*9868SRoger.Faulkner@Sun.COM {
62*9868SRoger.Faulkner@Sun.COM 	struct mnttab mt;
63*9868SRoger.Faulkner@Sun.COM 	struct mnttab mt_find;
64*9868SRoger.Faulkner@Sun.COM 	struct lofs_mnttab *lmt;
65*9868SRoger.Faulkner@Sun.COM 	struct lofs_mnttab *next;
66*9868SRoger.Faulkner@Sun.COM 	FILE *fp;
67*9868SRoger.Faulkner@Sun.COM 
68*9868SRoger.Faulkner@Sun.COM 	assert(MUTEX_HELD(&lofs_lock));
69*9868SRoger.Faulkner@Sun.COM 
70*9868SRoger.Faulkner@Sun.COM 	/* destroy the old cache */
71*9868SRoger.Faulkner@Sun.COM 	for (lmt = lofs_mnttab; lmt != NULL; lmt = next) {
72*9868SRoger.Faulkner@Sun.COM 		next = lmt->l_next;
73*9868SRoger.Faulkner@Sun.COM 		free(lmt->l_special);
74*9868SRoger.Faulkner@Sun.COM 		free(lmt->l_mountp);
75*9868SRoger.Faulkner@Sun.COM 		free(lmt);
76*9868SRoger.Faulkner@Sun.COM 	}
77*9868SRoger.Faulkner@Sun.COM 	lofs_mnttab = NULL;
78*9868SRoger.Faulkner@Sun.COM 
79*9868SRoger.Faulkner@Sun.COM 	/* prepare to create the new cache */
80*9868SRoger.Faulkner@Sun.COM 	if ((fp = fopen(MNTTAB, "r")) == NULL)
81*9868SRoger.Faulkner@Sun.COM 		return;
82*9868SRoger.Faulkner@Sun.COM 
83*9868SRoger.Faulkner@Sun.COM 	/*
84*9868SRoger.Faulkner@Sun.COM 	 * We only care about lofs mount points.  But we need to
85*9868SRoger.Faulkner@Sun.COM 	 * ignore lofs mounts where the source path is the same
86*9868SRoger.Faulkner@Sun.COM 	 * as the target path.  (This can happen when a non-global
87*9868SRoger.Faulkner@Sun.COM 	 * zone has a lofs mount of a global zone filesystem, since
88*9868SRoger.Faulkner@Sun.COM 	 * the source path can't expose information about global
89*9868SRoger.Faulkner@Sun.COM 	 * zone paths to the non-global zone.)
90*9868SRoger.Faulkner@Sun.COM 	 */
91*9868SRoger.Faulkner@Sun.COM 	bzero(&mt_find, sizeof (mt_find));
92*9868SRoger.Faulkner@Sun.COM 	mt_find.mnt_fstype = "lofs";
93*9868SRoger.Faulkner@Sun.COM 	while (getmntany(fp, &mt, &mt_find) == 0 &&
94*9868SRoger.Faulkner@Sun.COM 	    (strcmp(mt.mnt_fstype, "lofs") == 0) &&
95*9868SRoger.Faulkner@Sun.COM 	    (strcmp(mt.mnt_special, mt.mnt_mountp) != 0)) {
96*9868SRoger.Faulkner@Sun.COM 		if ((lmt = malloc(sizeof (struct lofs_mnttab))) == NULL)
97*9868SRoger.Faulkner@Sun.COM 			break;
98*9868SRoger.Faulkner@Sun.COM 		lmt->l_special = strdup(mt.mnt_special);
99*9868SRoger.Faulkner@Sun.COM 		lmt->l_mountp = strdup(mt.mnt_mountp);
100*9868SRoger.Faulkner@Sun.COM 		lmt->l_next = lofs_mnttab;
101*9868SRoger.Faulkner@Sun.COM 		lofs_mnttab = lmt;
102*9868SRoger.Faulkner@Sun.COM 	}
103*9868SRoger.Faulkner@Sun.COM 
104*9868SRoger.Faulkner@Sun.COM 	(void) fclose(fp);
105*9868SRoger.Faulkner@Sun.COM }
106*9868SRoger.Faulkner@Sun.COM 
107*9868SRoger.Faulkner@Sun.COM static const char *
lookup_lofs_mount_point(const char * mountp)108*9868SRoger.Faulkner@Sun.COM lookup_lofs_mount_point(const char *mountp)
109*9868SRoger.Faulkner@Sun.COM {
110*9868SRoger.Faulkner@Sun.COM 	struct lofs_mnttab *lmt;
111*9868SRoger.Faulkner@Sun.COM 
112*9868SRoger.Faulkner@Sun.COM 	assert(MUTEX_HELD(&lofs_lock));
113*9868SRoger.Faulkner@Sun.COM 
114*9868SRoger.Faulkner@Sun.COM 	for (lmt = lofs_mnttab; lmt != NULL; lmt = lmt->l_next) {
115*9868SRoger.Faulkner@Sun.COM 		if (strcmp(lmt->l_mountp, mountp) == 0)
116*9868SRoger.Faulkner@Sun.COM 			return (lmt->l_special);
117*9868SRoger.Faulkner@Sun.COM 	}
118*9868SRoger.Faulkner@Sun.COM 	return (NULL);
119*9868SRoger.Faulkner@Sun.COM }
120*9868SRoger.Faulkner@Sun.COM 
1217675SEdward.Pilatowicz@Sun.COM static path_node_t *
pn_push(path_node_t ** pnp,char * path)1227675SEdward.Pilatowicz@Sun.COM pn_push(path_node_t **pnp, char *path)
1237675SEdward.Pilatowicz@Sun.COM {
1247675SEdward.Pilatowicz@Sun.COM 	path_node_t *pn;
1257675SEdward.Pilatowicz@Sun.COM 
1267675SEdward.Pilatowicz@Sun.COM 	if ((pn = calloc(sizeof (path_node_t), 1)) == NULL)
1277675SEdward.Pilatowicz@Sun.COM 		return (NULL);
1287675SEdward.Pilatowicz@Sun.COM 
1297675SEdward.Pilatowicz@Sun.COM 	if ((pn->pn_path = strdup(path)) == NULL) {
1307675SEdward.Pilatowicz@Sun.COM 		free(pn);
1317675SEdward.Pilatowicz@Sun.COM 		return (NULL);
1327675SEdward.Pilatowicz@Sun.COM 	}
1337675SEdward.Pilatowicz@Sun.COM 	pn->pn_next = *pnp;
1347675SEdward.Pilatowicz@Sun.COM 	return (*pnp = pn);
1357675SEdward.Pilatowicz@Sun.COM }
1367675SEdward.Pilatowicz@Sun.COM 
1377675SEdward.Pilatowicz@Sun.COM static void
pn_free(path_node_t ** pnp)1387675SEdward.Pilatowicz@Sun.COM pn_free(path_node_t **pnp)
1397675SEdward.Pilatowicz@Sun.COM {
1407675SEdward.Pilatowicz@Sun.COM 	path_node_t *pn;
1417675SEdward.Pilatowicz@Sun.COM 
1427675SEdward.Pilatowicz@Sun.COM 	while (*pnp != NULL) {
1437675SEdward.Pilatowicz@Sun.COM 		pn = *pnp;
1447675SEdward.Pilatowicz@Sun.COM 		*pnp = pn->pn_next;
1457675SEdward.Pilatowicz@Sun.COM 		free(pn->pn_path);
1467675SEdward.Pilatowicz@Sun.COM 		free(pn);
1477675SEdward.Pilatowicz@Sun.COM 	}
1487675SEdward.Pilatowicz@Sun.COM }
1497675SEdward.Pilatowicz@Sun.COM 
1507675SEdward.Pilatowicz@Sun.COM static void
pn_free2(path_node_t ** pn1,path_node_t ** pn2)1517675SEdward.Pilatowicz@Sun.COM pn_free2(path_node_t **pn1, path_node_t **pn2)
1527675SEdward.Pilatowicz@Sun.COM {
1537675SEdward.Pilatowicz@Sun.COM 	pn_free(pn1);
1547675SEdward.Pilatowicz@Sun.COM 	pn_free(pn2);
1557675SEdward.Pilatowicz@Sun.COM }
1567675SEdward.Pilatowicz@Sun.COM 
1577675SEdward.Pilatowicz@Sun.COM static char *
pn_pop(path_node_t ** pnp,char * path)1587675SEdward.Pilatowicz@Sun.COM pn_pop(path_node_t **pnp, char *path)
1597675SEdward.Pilatowicz@Sun.COM {
1607675SEdward.Pilatowicz@Sun.COM 	path_node_t *pn;
1617675SEdward.Pilatowicz@Sun.COM 
1627675SEdward.Pilatowicz@Sun.COM 	if (*pnp == NULL)
1637675SEdward.Pilatowicz@Sun.COM 		return (NULL);
1647675SEdward.Pilatowicz@Sun.COM 
1657675SEdward.Pilatowicz@Sun.COM 	pn = *pnp;
1667675SEdward.Pilatowicz@Sun.COM 	*pnp = pn->pn_next;
1677675SEdward.Pilatowicz@Sun.COM 	pn->pn_next = NULL;
1687675SEdward.Pilatowicz@Sun.COM 
1697675SEdward.Pilatowicz@Sun.COM 	if (path == NULL) {
1707675SEdward.Pilatowicz@Sun.COM 		pn_free(&pn);
1717675SEdward.Pilatowicz@Sun.COM 		return (NULL);
1727675SEdward.Pilatowicz@Sun.COM 	}
1737675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(path, pn->pn_path, PATH_MAX);
1747675SEdward.Pilatowicz@Sun.COM 	pn_free(&pn);
1757675SEdward.Pilatowicz@Sun.COM 	return (path);
1767675SEdward.Pilatowicz@Sun.COM }
1777675SEdward.Pilatowicz@Sun.COM 
1787675SEdward.Pilatowicz@Sun.COM 
1797675SEdward.Pilatowicz@Sun.COM /*
1807675SEdward.Pilatowicz@Sun.COM  * Libzonecfg.so links against libproc, so libproc can't link against
1817675SEdward.Pilatowicz@Sun.COM  * libzonecfg.so.  Also, libzonecfg.so is optional and might not be
1827675SEdward.Pilatowicz@Sun.COM  * installed.  Hence instead of relying on linking to access libzonecfg.so,
1837675SEdward.Pilatowicz@Sun.COM  * we'll try dlopening it here.  This trick is borrowed from
1847675SEdward.Pilatowicz@Sun.COM  * libc`zone_get_id(), see that function for more detailed comments.
1857675SEdward.Pilatowicz@Sun.COM  */
1867675SEdward.Pilatowicz@Sun.COM static int
i_zone_get_zonepath(char * zone_name,char * zonepath,size_t rp_sz)1877675SEdward.Pilatowicz@Sun.COM i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
1887675SEdward.Pilatowicz@Sun.COM {
1897675SEdward.Pilatowicz@Sun.COM 	typedef	int (*zone_get_zonepath_t)(char *, char *, size_t);
1907675SEdward.Pilatowicz@Sun.COM 	static zone_get_zonepath_t zone_get_zonepath_fp = NULL;
1917675SEdward.Pilatowicz@Sun.COM 
1927675SEdward.Pilatowicz@Sun.COM 	if (zone_get_zonepath_fp == NULL) {
1937675SEdward.Pilatowicz@Sun.COM 		/* There's no harm in doing this multiple times. */
1947675SEdward.Pilatowicz@Sun.COM 		void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY);
1957675SEdward.Pilatowicz@Sun.COM 		void *sym = (void *)(-1);
1967675SEdward.Pilatowicz@Sun.COM 		if (dlhandle != NULL &&
1977675SEdward.Pilatowicz@Sun.COM 		    (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) {
1987675SEdward.Pilatowicz@Sun.COM 			sym = (void *)(-1);
1997675SEdward.Pilatowicz@Sun.COM 			(void) dlclose(dlhandle);
2007675SEdward.Pilatowicz@Sun.COM 		}
2017675SEdward.Pilatowicz@Sun.COM 		zone_get_zonepath_fp = (zone_get_zonepath_t)sym;
2027675SEdward.Pilatowicz@Sun.COM 	}
2037675SEdward.Pilatowicz@Sun.COM 
2047675SEdward.Pilatowicz@Sun.COM 	/* If we've successfully loaded it, call the real function */
2057675SEdward.Pilatowicz@Sun.COM 	if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1))
2067675SEdward.Pilatowicz@Sun.COM 		return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz));
2077675SEdward.Pilatowicz@Sun.COM 	return (Z_NO_ZONE);
2087675SEdward.Pilatowicz@Sun.COM }
2097675SEdward.Pilatowicz@Sun.COM 
2107675SEdward.Pilatowicz@Sun.COM char *
Pbrandname(struct ps_prochandle * P,char * buf,size_t buflen)2117675SEdward.Pilatowicz@Sun.COM Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen)
2127675SEdward.Pilatowicz@Sun.COM {
2137675SEdward.Pilatowicz@Sun.COM 	long	addr;
2147675SEdward.Pilatowicz@Sun.COM 
2157675SEdward.Pilatowicz@Sun.COM 	if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1)
2167675SEdward.Pilatowicz@Sun.COM 		return (NULL);
2177675SEdward.Pilatowicz@Sun.COM 
2187675SEdward.Pilatowicz@Sun.COM 	if (Pread_string(P, buf, buflen, addr) == -1)
2197675SEdward.Pilatowicz@Sun.COM 		return (NULL);
2207675SEdward.Pilatowicz@Sun.COM 
2217675SEdward.Pilatowicz@Sun.COM 	return (buf);
2227675SEdward.Pilatowicz@Sun.COM }
2237675SEdward.Pilatowicz@Sun.COM 
2247675SEdward.Pilatowicz@Sun.COM /*
2257675SEdward.Pilatowicz@Sun.COM  * Get the zone name from the core file if we have it; look up the
2267675SEdward.Pilatowicz@Sun.COM  * name based on the zone id if this is a live process.
2277675SEdward.Pilatowicz@Sun.COM  */
2287675SEdward.Pilatowicz@Sun.COM char *
Pzonename(struct ps_prochandle * P,char * s,size_t n)2297675SEdward.Pilatowicz@Sun.COM Pzonename(struct ps_prochandle *P, char *s, size_t n)
2307675SEdward.Pilatowicz@Sun.COM {
2317675SEdward.Pilatowicz@Sun.COM 	if (P->state == PS_IDLE) {
2327675SEdward.Pilatowicz@Sun.COM 		errno = ENODATA;
2337675SEdward.Pilatowicz@Sun.COM 		return (NULL);
2347675SEdward.Pilatowicz@Sun.COM 	}
2357675SEdward.Pilatowicz@Sun.COM 
2367675SEdward.Pilatowicz@Sun.COM 	if (P->state == PS_DEAD) {
2377675SEdward.Pilatowicz@Sun.COM 		if (P->core->core_zonename == NULL) {
2387675SEdward.Pilatowicz@Sun.COM 			errno = ENODATA;
2397675SEdward.Pilatowicz@Sun.COM 			return (NULL);
2407675SEdward.Pilatowicz@Sun.COM 		}
2417675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, P->core->core_zonename, n);
2427675SEdward.Pilatowicz@Sun.COM 	} else {
2437675SEdward.Pilatowicz@Sun.COM 		if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0)
2447675SEdward.Pilatowicz@Sun.COM 			return (NULL);
2457675SEdward.Pilatowicz@Sun.COM 		s[n - 1] = '\0';
2467675SEdward.Pilatowicz@Sun.COM 	}
2477675SEdward.Pilatowicz@Sun.COM 	return (s);
2487675SEdward.Pilatowicz@Sun.COM }
2497675SEdward.Pilatowicz@Sun.COM 
2507675SEdward.Pilatowicz@Sun.COM char *
Pzoneroot(struct ps_prochandle * P,char * s,size_t n)2517675SEdward.Pilatowicz@Sun.COM Pzoneroot(struct ps_prochandle *P, char *s, size_t n)
2527675SEdward.Pilatowicz@Sun.COM {
2537675SEdward.Pilatowicz@Sun.COM 	char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX];
2547675SEdward.Pilatowicz@Sun.COM 	int rv;
2557675SEdward.Pilatowicz@Sun.COM 
2567675SEdward.Pilatowicz@Sun.COM 	if (P->zoneroot != NULL) {
2577675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, P->zoneroot, n);
2587675SEdward.Pilatowicz@Sun.COM 		return (s);
2597675SEdward.Pilatowicz@Sun.COM 	}
2607675SEdward.Pilatowicz@Sun.COM 
2617675SEdward.Pilatowicz@Sun.COM 	if ((Pzonename(P, zname, sizeof (zname)) == NULL) ||
2627675SEdward.Pilatowicz@Sun.COM 	    (strcmp(zname, GLOBAL_ZONENAME) == 0)) {
2637675SEdward.Pilatowicz@Sun.COM 		if ((P->zoneroot = strdup("")) == NULL) {
2647675SEdward.Pilatowicz@Sun.COM 			errno = ENOMEM;
2657675SEdward.Pilatowicz@Sun.COM 			return (NULL);
2667675SEdward.Pilatowicz@Sun.COM 		}
2677675SEdward.Pilatowicz@Sun.COM 		dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME);
2687675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, P->zoneroot, n);
2697675SEdward.Pilatowicz@Sun.COM 		return (s);
2707675SEdward.Pilatowicz@Sun.COM 	}
2717675SEdward.Pilatowicz@Sun.COM 
2727675SEdward.Pilatowicz@Sun.COM 	if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) {
2737675SEdward.Pilatowicz@Sun.COM 		if ((P->zoneroot = strdup("")) == NULL) {
2747675SEdward.Pilatowicz@Sun.COM 			errno = ENOMEM;
2757675SEdward.Pilatowicz@Sun.COM 			return (NULL);
2767675SEdward.Pilatowicz@Sun.COM 		}
2777675SEdward.Pilatowicz@Sun.COM 		dprintf(
2787675SEdward.Pilatowicz@Sun.COM 		    "Pzoneroot zone not found '%s', defaulting to '%s'\n",
2797675SEdward.Pilatowicz@Sun.COM 		    zname, GLOBAL_ZONENAME);
2807675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, P->zoneroot, n);
2817675SEdward.Pilatowicz@Sun.COM 		return (s);
2827675SEdward.Pilatowicz@Sun.COM 	}
2837675SEdward.Pilatowicz@Sun.COM 	(void) strlcat(zpath, "/root", sizeof (zpath));
2847675SEdward.Pilatowicz@Sun.COM 
2857675SEdward.Pilatowicz@Sun.COM 	if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) {
2867675SEdward.Pilatowicz@Sun.COM 		if ((P->zoneroot = strdup("")) == NULL) {
2877675SEdward.Pilatowicz@Sun.COM 			errno = ENOMEM;
2887675SEdward.Pilatowicz@Sun.COM 			return (NULL);
2897675SEdward.Pilatowicz@Sun.COM 		}
2907675SEdward.Pilatowicz@Sun.COM 		dprintf(
2917675SEdward.Pilatowicz@Sun.COM 		    "Pzoneroot can't access '%s:%s', defaulting to '%s'\n",
2927675SEdward.Pilatowicz@Sun.COM 		    zname, zpath, GLOBAL_ZONENAME);
2937675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, P->zoneroot, n);
2947675SEdward.Pilatowicz@Sun.COM 		return (s);
2957675SEdward.Pilatowicz@Sun.COM 	}
2967675SEdward.Pilatowicz@Sun.COM 	tmp[rv] = '\0';
2977675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(zpath, tmp, sizeof (zpath));
2987675SEdward.Pilatowicz@Sun.COM 
2997675SEdward.Pilatowicz@Sun.COM 	if ((P->zoneroot = strdup(zpath)) == NULL) {
3007675SEdward.Pilatowicz@Sun.COM 		errno = ENOMEM;
3017675SEdward.Pilatowicz@Sun.COM 		return (NULL);
3027675SEdward.Pilatowicz@Sun.COM 	}
3037675SEdward.Pilatowicz@Sun.COM 	dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath);
3047675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(s, P->zoneroot, n);
3057675SEdward.Pilatowicz@Sun.COM 	return (s);
3067675SEdward.Pilatowicz@Sun.COM }
3077675SEdward.Pilatowicz@Sun.COM 
3087675SEdward.Pilatowicz@Sun.COM /*
3097675SEdward.Pilatowicz@Sun.COM  * Plofspath() takes a path, "path",  and removes any lofs components from
3107675SEdward.Pilatowicz@Sun.COM  * that path.  The resultant path (if different from the starting path)
3117675SEdward.Pilatowicz@Sun.COM  * is placed in "s", which is limited to "n" characters, and the return
3127675SEdward.Pilatowicz@Sun.COM  * value is the pointer s.  If there are no lofs components in the path
3137675SEdward.Pilatowicz@Sun.COM  * the NULL is returned and s is not modified.  It's ok for "path" and
3147675SEdward.Pilatowicz@Sun.COM  * "s" to be the same pointer.  (ie, the results can be stored directly
3157675SEdward.Pilatowicz@Sun.COM  * in the input buffer.)  The path that is passed in must be an absolute
3167675SEdward.Pilatowicz@Sun.COM  * path.
3177675SEdward.Pilatowicz@Sun.COM  *
3187675SEdward.Pilatowicz@Sun.COM  * Example:
3197675SEdward.Pilatowicz@Sun.COM  *	if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/"
3207675SEdward.Pilatowicz@Sun.COM  *	then "/candy/bar/" will be written into "s" and "s" will be returned.
3217675SEdward.Pilatowicz@Sun.COM  */
3227675SEdward.Pilatowicz@Sun.COM char *
Plofspath(const char * path,char * s,size_t n)3237675SEdward.Pilatowicz@Sun.COM Plofspath(const char *path, char *s, size_t n)
3247675SEdward.Pilatowicz@Sun.COM {
3257675SEdward.Pilatowicz@Sun.COM 	char tmp[PATH_MAX + 1];
326*9868SRoger.Faulkner@Sun.COM 	struct stat64 statb;
327*9868SRoger.Faulkner@Sun.COM 	const char *special;
3287675SEdward.Pilatowicz@Sun.COM 	char *p, *p2;
3297675SEdward.Pilatowicz@Sun.COM 	int rv;
3307675SEdward.Pilatowicz@Sun.COM 
3317675SEdward.Pilatowicz@Sun.COM 	dprintf("Plofspath path '%s'\n", path);
3327675SEdward.Pilatowicz@Sun.COM 
3337675SEdward.Pilatowicz@Sun.COM 	/* We only deal with absolute paths */
3347675SEdward.Pilatowicz@Sun.COM 	if (path[0] != '/')
3357675SEdward.Pilatowicz@Sun.COM 		return (NULL);
3367675SEdward.Pilatowicz@Sun.COM 
3377675SEdward.Pilatowicz@Sun.COM 	/* Make a copy of the path so that we can muck with it */
3387675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(tmp, path, sizeof (tmp) - 1);
3397675SEdward.Pilatowicz@Sun.COM 
3407675SEdward.Pilatowicz@Sun.COM 	/*
3417675SEdward.Pilatowicz@Sun.COM 	 * Use resolvepath() to make sure there are no consecutive or
3427675SEdward.Pilatowicz@Sun.COM 	 * trailing '/'s in the path.
3437675SEdward.Pilatowicz@Sun.COM 	 */
3447675SEdward.Pilatowicz@Sun.COM 	if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
3457675SEdward.Pilatowicz@Sun.COM 		tmp[rv] = '\0';
3467675SEdward.Pilatowicz@Sun.COM 
347*9868SRoger.Faulkner@Sun.COM 	(void) mutex_lock(&lofs_lock);
348*9868SRoger.Faulkner@Sun.COM 
349*9868SRoger.Faulkner@Sun.COM 	/*
350*9868SRoger.Faulkner@Sun.COM 	 * If /etc/mnttab has been modified since the last time
351*9868SRoger.Faulkner@Sun.COM 	 * we looked, then rebuild the lofs lookup cache.
352*9868SRoger.Faulkner@Sun.COM 	 */
353*9868SRoger.Faulkner@Sun.COM 	if (stat64(MNTTAB, &statb) == 0 &&
354*9868SRoger.Faulkner@Sun.COM 	    (statb.st_mtim.tv_sec != lofs_mstat.st_mtim.tv_sec ||
355*9868SRoger.Faulkner@Sun.COM 	    statb.st_mtim.tv_nsec != lofs_mstat.st_mtim.tv_nsec ||
356*9868SRoger.Faulkner@Sun.COM 	    statb.st_ctim.tv_sec != lofs_mstat.st_ctim.tv_sec ||
357*9868SRoger.Faulkner@Sun.COM 	    statb.st_ctim.tv_nsec != lofs_mstat.st_ctim.tv_nsec)) {
358*9868SRoger.Faulkner@Sun.COM 		lofs_mstat = statb;
359*9868SRoger.Faulkner@Sun.COM 		rebuild_lofs_cache();
360*9868SRoger.Faulkner@Sun.COM 	}
361*9868SRoger.Faulkner@Sun.COM 
3627675SEdward.Pilatowicz@Sun.COM 	/*
3637675SEdward.Pilatowicz@Sun.COM 	 * So now we're going to search the path for any components that
3647675SEdward.Pilatowicz@Sun.COM 	 * might be lofs mounts.  We'll start out search from the full
3657675SEdward.Pilatowicz@Sun.COM 	 * path and then step back through each parent directly till
3667675SEdward.Pilatowicz@Sun.COM 	 * we reach the root.  If we find a lofs mount point in the path
3677675SEdward.Pilatowicz@Sun.COM 	 * then we'll replace the initial portion of the path (up
3687675SEdward.Pilatowicz@Sun.COM 	 * to that mount point) with the source of that mount point
3697675SEdward.Pilatowicz@Sun.COM 	 * and then start our search over again.
3707675SEdward.Pilatowicz@Sun.COM 	 *
3717675SEdward.Pilatowicz@Sun.COM 	 * Here's some of the variables we're going to use:
3727675SEdward.Pilatowicz@Sun.COM 	 *
3737675SEdward.Pilatowicz@Sun.COM 	 *	tmp - A pointer to our working copy of the path.  Sometimes
3747675SEdward.Pilatowicz@Sun.COM 	 *		this path will be divided into two strings by a
3757675SEdward.Pilatowicz@Sun.COM 	 *		'\0' (NUL) character.  The first string is the
3767675SEdward.Pilatowicz@Sun.COM 	 *		component we're currently checking and the second
3777675SEdward.Pilatowicz@Sun.COM 	 *		string is the path components we've already checked.
3787675SEdward.Pilatowicz@Sun.COM 	 *
3797675SEdward.Pilatowicz@Sun.COM 	 *	p - A pointer to the last '/' seen in the string.
3807675SEdward.Pilatowicz@Sun.COM 	 *
3817675SEdward.Pilatowicz@Sun.COM 	 *	p[1] - A pointer to the component of the string we've already
3827675SEdward.Pilatowicz@Sun.COM 	 *		checked.
3837675SEdward.Pilatowicz@Sun.COM 	 *
3847675SEdward.Pilatowicz@Sun.COM 	 * Initially, p will point to the end of our path and p[1] will point
3857675SEdward.Pilatowicz@Sun.COM 	 * to an extra '\0' (NUL) that we'll append to the end of the string.
3867675SEdward.Pilatowicz@Sun.COM 	 * (This is why we declared tmp with a size of PATH_MAX + 1).
3877675SEdward.Pilatowicz@Sun.COM 	 */
3887675SEdward.Pilatowicz@Sun.COM 	p = &tmp[strlen(tmp)];
3897675SEdward.Pilatowicz@Sun.COM 	p[1] = '\0';
3907675SEdward.Pilatowicz@Sun.COM 	for (;;) {
391*9868SRoger.Faulkner@Sun.COM 		if ((special = lookup_lofs_mount_point(tmp)) != NULL) {
3927675SEdward.Pilatowicz@Sun.COM 			char tmp2[PATH_MAX + 1];
3937675SEdward.Pilatowicz@Sun.COM 
3947675SEdward.Pilatowicz@Sun.COM 			/*
3957675SEdward.Pilatowicz@Sun.COM 			 * We found a lofs mount.  Update the path that we're
3967675SEdward.Pilatowicz@Sun.COM 			 * checking and start over.  This means append the
3977675SEdward.Pilatowicz@Sun.COM 			 * portion of the path we've already checked to the
3987675SEdward.Pilatowicz@Sun.COM 			 * source of the lofs mount and re-start this entire
3997675SEdward.Pilatowicz@Sun.COM 			 * lofs resolution loop.  Use resolvepath() to make
4007675SEdward.Pilatowicz@Sun.COM 			 * sure there are no consecutive or trailing '/'s
4017675SEdward.Pilatowicz@Sun.COM 			 * in the path.
4027675SEdward.Pilatowicz@Sun.COM 			 */
403*9868SRoger.Faulkner@Sun.COM 			(void) strlcpy(tmp2, special, sizeof (tmp2) - 1);
4047675SEdward.Pilatowicz@Sun.COM 			(void) strlcat(tmp2, "/", sizeof (tmp2) - 1);
4057675SEdward.Pilatowicz@Sun.COM 			(void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1);
4067675SEdward.Pilatowicz@Sun.COM 			(void) strlcpy(tmp, tmp2, sizeof (tmp) - 1);
4077675SEdward.Pilatowicz@Sun.COM 			if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
4087675SEdward.Pilatowicz@Sun.COM 				tmp[rv] = '\0';
4097675SEdward.Pilatowicz@Sun.COM 			p = &tmp[strlen(tmp)];
4107675SEdward.Pilatowicz@Sun.COM 			p[1] = '\0';
4117675SEdward.Pilatowicz@Sun.COM 			continue;
4127675SEdward.Pilatowicz@Sun.COM 		}
4137675SEdward.Pilatowicz@Sun.COM 
4147675SEdward.Pilatowicz@Sun.COM 		/* No lofs mount found */
4157675SEdward.Pilatowicz@Sun.COM 		if ((p2 = strrchr(tmp, '/')) == NULL) {
4167675SEdward.Pilatowicz@Sun.COM 			char tmp2[PATH_MAX];
4177675SEdward.Pilatowicz@Sun.COM 
418*9868SRoger.Faulkner@Sun.COM 			(void) mutex_unlock(&lofs_lock);
419*9868SRoger.Faulkner@Sun.COM 
4207675SEdward.Pilatowicz@Sun.COM 			/*
4217675SEdward.Pilatowicz@Sun.COM 			 * We know that tmp was an absolute path, so if we
4227675SEdward.Pilatowicz@Sun.COM 			 * made it here we know that (p == tmp) and that
4237675SEdward.Pilatowicz@Sun.COM 			 * (*p == '\0').  This means that we've managed
4247675SEdward.Pilatowicz@Sun.COM 			 * to check the whole path and so we're done.
4257675SEdward.Pilatowicz@Sun.COM 			 */
4267675SEdward.Pilatowicz@Sun.COM 			assert(p == tmp);
4277675SEdward.Pilatowicz@Sun.COM 			assert(p[0] == '\0');
4287675SEdward.Pilatowicz@Sun.COM 
4297675SEdward.Pilatowicz@Sun.COM 			/* Restore the leading '/' in the path */
4307675SEdward.Pilatowicz@Sun.COM 			p[0] = '/';
4317675SEdward.Pilatowicz@Sun.COM 
4327675SEdward.Pilatowicz@Sun.COM 			if (strcmp(tmp, path) == 0) {
4337675SEdward.Pilatowicz@Sun.COM 				/* The path didn't change */
4347675SEdward.Pilatowicz@Sun.COM 				return (NULL);
4357675SEdward.Pilatowicz@Sun.COM 			}
4367675SEdward.Pilatowicz@Sun.COM 
4377675SEdward.Pilatowicz@Sun.COM 			/*
4387675SEdward.Pilatowicz@Sun.COM 			 * It's possible that lofs source path we just
4397675SEdward.Pilatowicz@Sun.COM 			 * obtained contains a symbolic link.  Use
4407675SEdward.Pilatowicz@Sun.COM 			 * resolvepath() to clean it up.
4417675SEdward.Pilatowicz@Sun.COM 			 */
4427675SEdward.Pilatowicz@Sun.COM 			(void) strlcpy(tmp2, tmp, sizeof (tmp2));
4437675SEdward.Pilatowicz@Sun.COM 			if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0)
4447675SEdward.Pilatowicz@Sun.COM 				tmp[rv] = '\0';
4457675SEdward.Pilatowicz@Sun.COM 
4467675SEdward.Pilatowicz@Sun.COM 			/*
4477675SEdward.Pilatowicz@Sun.COM 			 * It's always possible that our lofs source path is
4487675SEdward.Pilatowicz@Sun.COM 			 * actually another lofs mount.  So call ourselves
4497675SEdward.Pilatowicz@Sun.COM 			 * recursively to resolve that path.
4507675SEdward.Pilatowicz@Sun.COM 			 */
4517675SEdward.Pilatowicz@Sun.COM 			(void) Plofspath(tmp, tmp, PATH_MAX);
4527675SEdward.Pilatowicz@Sun.COM 
4537675SEdward.Pilatowicz@Sun.COM 			/* Copy out our final resolved lofs source path */
4547675SEdward.Pilatowicz@Sun.COM 			(void) strlcpy(s, tmp, n);
4557675SEdward.Pilatowicz@Sun.COM 			dprintf("Plofspath path result '%s'\n", s);
4567675SEdward.Pilatowicz@Sun.COM 			return (s);
4577675SEdward.Pilatowicz@Sun.COM 		}
4587675SEdward.Pilatowicz@Sun.COM 
4597675SEdward.Pilatowicz@Sun.COM 		/*
4607675SEdward.Pilatowicz@Sun.COM 		 * So the path we just checked is not a lofs mount.  Next we
4617675SEdward.Pilatowicz@Sun.COM 		 * want to check the parent path component for a lofs mount.
4627675SEdward.Pilatowicz@Sun.COM 		 *
4637675SEdward.Pilatowicz@Sun.COM 		 * First, restore any '/' that we replaced with a '\0' (NUL).
4647675SEdward.Pilatowicz@Sun.COM 		 * We can determine if we should do this by looking at p[1].
4657675SEdward.Pilatowicz@Sun.COM 		 * If p[1] points to a '\0' (NUL) then we know that p points
4667675SEdward.Pilatowicz@Sun.COM 		 * to the end of the string and there is no '/' to restore.
4677675SEdward.Pilatowicz@Sun.COM 		 * if p[1] doesn't point to a '\0' (NUL) then it points to
4687675SEdward.Pilatowicz@Sun.COM 		 * the part of the path that we've already verified so there
4697675SEdward.Pilatowicz@Sun.COM 		 * is a '/' to restore.
4707675SEdward.Pilatowicz@Sun.COM 		 */
4717675SEdward.Pilatowicz@Sun.COM 		if (p[1] != '\0')
4727675SEdward.Pilatowicz@Sun.COM 			p[0] = '/';
4737675SEdward.Pilatowicz@Sun.COM 
4747675SEdward.Pilatowicz@Sun.COM 		/*
4757675SEdward.Pilatowicz@Sun.COM 		 * Second, replace the last '/' in the part of the path
4767675SEdward.Pilatowicz@Sun.COM 		 * that we've already checked with a '\0' (NUL) so that
4777675SEdward.Pilatowicz@Sun.COM 		 * when we loop around we check the parent component of the
4787675SEdward.Pilatowicz@Sun.COM 		 * path.
4797675SEdward.Pilatowicz@Sun.COM 		 */
4807675SEdward.Pilatowicz@Sun.COM 		p2[0] = '\0';
4817675SEdward.Pilatowicz@Sun.COM 		p = p2;
4827675SEdward.Pilatowicz@Sun.COM 	}
4837675SEdward.Pilatowicz@Sun.COM 	/*NOTREACHED*/
4847675SEdward.Pilatowicz@Sun.COM }
4857675SEdward.Pilatowicz@Sun.COM 
4867675SEdward.Pilatowicz@Sun.COM /*
4877675SEdward.Pilatowicz@Sun.COM  * Pzonepath() - Way too much code to attempt to derive the full path of
4887675SEdward.Pilatowicz@Sun.COM  * an object within a zone.
4897675SEdward.Pilatowicz@Sun.COM  *
4907675SEdward.Pilatowicz@Sun.COM  * Pzonepath() takes a path and attempts to resolve it relative to the
4917675SEdward.Pilatowicz@Sun.COM  * root associated with the current process handle.  If it fails it will
4927675SEdward.Pilatowicz@Sun.COM  * not update the results string.  It is safe to specify the same pointer
4937675SEdward.Pilatowicz@Sun.COM  * for the file string and the results string.
4947675SEdward.Pilatowicz@Sun.COM  *
4957675SEdward.Pilatowicz@Sun.COM  * Doing this resolution is more difficult than it initially sounds.
4967675SEdward.Pilatowicz@Sun.COM  * We can't simply append the file path to the zone root, because in
4977675SEdward.Pilatowicz@Sun.COM  * a root directory, '..' is treated the same as '.'.  Also, symbolic
4987675SEdward.Pilatowicz@Sun.COM  * links that specify an absolute path need to be interpreted relative
4997675SEdward.Pilatowicz@Sun.COM  * to the zone root.
5007675SEdward.Pilatowicz@Sun.COM  *
5017675SEdward.Pilatowicz@Sun.COM  * It seems like perhaps we could do a chroot(<zone root>) followed by a
5027675SEdward.Pilatowicz@Sun.COM  * resolvepath().  But we can't do this because chroot requires special
5037675SEdward.Pilatowicz@Sun.COM  * privileges and affects the entire process.  Perhaps if there was a
5047675SEdward.Pilatowicz@Sun.COM  * special version of resolvepath() which took an addition root path
5057675SEdward.Pilatowicz@Sun.COM  * we could use that, but this isn't ideal either.  The reason is
5067675SEdward.Pilatowicz@Sun.COM  * that we want to have special handling for native paths.  (A native path
5077675SEdward.Pilatowicz@Sun.COM  * is a path that begins with "/native/" or "/.SUNWnative/".)  Native
5087675SEdward.Pilatowicz@Sun.COM  * paths could be passed explicity to this function or could be embedded
5097675SEdward.Pilatowicz@Sun.COM  * in a symlink that is part of the path passed into this function.
5107675SEdward.Pilatowicz@Sun.COM  * These paths are always lofs mounts of global zone paths, but lofs
5117675SEdward.Pilatowicz@Sun.COM  * mounts only exist when a zone is booted.  So if we were to try to do
5127675SEdward.Pilatowicz@Sun.COM  * a resolvepath() on a native path when the zone wasn't booted the
5137675SEdward.Pilatowicz@Sun.COM  * resolvepath() would fail even though we know that the components
5147675SEdward.Pilatowicz@Sun.COM  * exists in the global zone.
5157675SEdward.Pilatowicz@Sun.COM  *
5167675SEdward.Pilatowicz@Sun.COM  * Given all these constraints, we just implement a path walking function
5177675SEdward.Pilatowicz@Sun.COM  * that resolves a file path relative to a zone root by manually inspecting
5187675SEdward.Pilatowicz@Sun.COM  * each of the path components and verifying its existence.  This means that
5197675SEdward.Pilatowicz@Sun.COM  * we must have access to the zone and that all the components of the
5207675SEdward.Pilatowicz@Sun.COM  * path must exist for this operation to succeed.
5217675SEdward.Pilatowicz@Sun.COM  */
5227675SEdward.Pilatowicz@Sun.COM char *
Pzonepath(struct ps_prochandle * P,const char * path,char * s,size_t n)5237675SEdward.Pilatowicz@Sun.COM Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n)
5247675SEdward.Pilatowicz@Sun.COM {
5257675SEdward.Pilatowicz@Sun.COM 	char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX];
5267675SEdward.Pilatowicz@Sun.COM 	path_node_t *pn_stack = NULL, *pn_links = NULL, *pn;
5277675SEdward.Pilatowicz@Sun.COM 	struct stat64 sb;
5287675SEdward.Pilatowicz@Sun.COM 	char *p;
5297675SEdward.Pilatowicz@Sun.COM 	int i, rv;
5307675SEdward.Pilatowicz@Sun.COM 
5317675SEdward.Pilatowicz@Sun.COM 	dprintf("Pzonepath lookup '%s'\n", path);
5327675SEdward.Pilatowicz@Sun.COM 
5337675SEdward.Pilatowicz@Sun.COM 	/* First lookup the zone root */
5347675SEdward.Pilatowicz@Sun.COM 	if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL)
5357675SEdward.Pilatowicz@Sun.COM 		return (NULL);
5367675SEdward.Pilatowicz@Sun.COM 
5377675SEdward.Pilatowicz@Sun.COM 	/*
5387675SEdward.Pilatowicz@Sun.COM 	 * Make a temporary copy of the path specified.
5397675SEdward.Pilatowicz@Sun.COM 	 * If it's a relative path then make it into an absolute path.
5407675SEdward.Pilatowicz@Sun.COM 	 */
5417675SEdward.Pilatowicz@Sun.COM 	tmp[0] = '\0';
5427675SEdward.Pilatowicz@Sun.COM 	if (path[0] != '/')
5437675SEdward.Pilatowicz@Sun.COM 		(void) strlcat(tmp, "/", sizeof (tmp));
5447675SEdward.Pilatowicz@Sun.COM 	(void) strlcat(tmp, path, sizeof (tmp));
5457675SEdward.Pilatowicz@Sun.COM 
5467675SEdward.Pilatowicz@Sun.COM 	/*
5477675SEdward.Pilatowicz@Sun.COM 	 * If the path that was passed in is the zone root, we're done.
5487675SEdward.Pilatowicz@Sun.COM 	 * If the path that was passed in already contains the zone root
5497675SEdward.Pilatowicz@Sun.COM 	 * then strip the zone root out and verify the rest of the path.
5507675SEdward.Pilatowicz@Sun.COM 	 */
5517675SEdward.Pilatowicz@Sun.COM 	if (strcmp(tmp, zroot) == 0) {
5527675SEdward.Pilatowicz@Sun.COM 		(void) Plofspath(zroot, zroot, sizeof (zroot));
5537675SEdward.Pilatowicz@Sun.COM 		dprintf("Pzonepath found zone path (1) '%s'\n", zroot);
5547675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, zroot, n);
5557675SEdward.Pilatowicz@Sun.COM 		return (s);
5567675SEdward.Pilatowicz@Sun.COM 	}
5577675SEdward.Pilatowicz@Sun.COM 	i = strlen(zroot);
5587675SEdward.Pilatowicz@Sun.COM 	if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/'))
5597675SEdward.Pilatowicz@Sun.COM 		(void) memmove(tmp, tmp + i, strlen(tmp + i) + 1);
5607675SEdward.Pilatowicz@Sun.COM 
5617675SEdward.Pilatowicz@Sun.COM 	/* If no path is passed in, then it maps to the zone root */
5627675SEdward.Pilatowicz@Sun.COM 	if (strlen(tmp) == 0) {
5637675SEdward.Pilatowicz@Sun.COM 		(void) Plofspath(zroot, zroot, sizeof (zroot));
5647675SEdward.Pilatowicz@Sun.COM 		dprintf("Pzonepath found zone path (2) '%s'\n", zroot);
5657675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, zroot, n);
5667675SEdward.Pilatowicz@Sun.COM 		return (s);
5677675SEdward.Pilatowicz@Sun.COM 	}
5687675SEdward.Pilatowicz@Sun.COM 
5697675SEdward.Pilatowicz@Sun.COM 	/*
5707675SEdward.Pilatowicz@Sun.COM 	 * Push each path component that we plan to verify onto a stack of
5717675SEdward.Pilatowicz@Sun.COM 	 * path components, with parent components at the top of the stack.
5727675SEdward.Pilatowicz@Sun.COM 	 * So for example, if we're going to verify the path /foo/bar/bang
5737675SEdward.Pilatowicz@Sun.COM 	 * then our stack will look like:
5747675SEdward.Pilatowicz@Sun.COM 	 *	foo	(top)
5757675SEdward.Pilatowicz@Sun.COM 	 *	bar
5767675SEdward.Pilatowicz@Sun.COM 	 *	bang	(bottom)
5777675SEdward.Pilatowicz@Sun.COM 	 */
5787675SEdward.Pilatowicz@Sun.COM 	while ((p = strrchr(tmp, '/')) != NULL) {
5797675SEdward.Pilatowicz@Sun.COM 		*p = '\0';
5807675SEdward.Pilatowicz@Sun.COM 		if (pn_push(&pn_stack, &p[1]) != NULL)
5817675SEdward.Pilatowicz@Sun.COM 			continue;
5827675SEdward.Pilatowicz@Sun.COM 		pn_free(&pn_stack);
5837675SEdward.Pilatowicz@Sun.COM 		return (NULL);
5847675SEdward.Pilatowicz@Sun.COM 	}
5857675SEdward.Pilatowicz@Sun.COM 
5867675SEdward.Pilatowicz@Sun.COM 	/* We're going to store the final zone relative path in zpath */
5877675SEdward.Pilatowicz@Sun.COM 	*zpath = '\0';
5887675SEdward.Pilatowicz@Sun.COM 
5897675SEdward.Pilatowicz@Sun.COM 	while (pn_pop(&pn_stack, tmp) != NULL) {
5907675SEdward.Pilatowicz@Sun.COM 		/*
5917675SEdward.Pilatowicz@Sun.COM 		 * Drop zero length path components (which come from
5927675SEdward.Pilatowicz@Sun.COM 		 * consecutive '/'s) and '.' path components.
5937675SEdward.Pilatowicz@Sun.COM 		 */
5947675SEdward.Pilatowicz@Sun.COM 		if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0))
5957675SEdward.Pilatowicz@Sun.COM 			continue;
5967675SEdward.Pilatowicz@Sun.COM 
5977675SEdward.Pilatowicz@Sun.COM 		/*
5987675SEdward.Pilatowicz@Sun.COM 		 * Check the current path component for '..', if found
5997675SEdward.Pilatowicz@Sun.COM 		 * drop any previous path component.
6007675SEdward.Pilatowicz@Sun.COM 		 */
6017675SEdward.Pilatowicz@Sun.COM 		if (strcmp(tmp, "..") == 0) {
6027675SEdward.Pilatowicz@Sun.COM 			if ((p = strrchr(zpath, '/')) != NULL)
6037675SEdward.Pilatowicz@Sun.COM 				*p = '\0';
6047675SEdward.Pilatowicz@Sun.COM 			continue;
6057675SEdward.Pilatowicz@Sun.COM 		}
6067675SEdward.Pilatowicz@Sun.COM 
6077675SEdward.Pilatowicz@Sun.COM 		/* The path we want to verify now is zpath + / + tmp. */
6087675SEdward.Pilatowicz@Sun.COM 		(void) strlcat(zpath, "/", sizeof (zpath));
6097675SEdward.Pilatowicz@Sun.COM 		(void) strlcat(zpath, tmp, sizeof (zpath));
6107675SEdward.Pilatowicz@Sun.COM 
6117675SEdward.Pilatowicz@Sun.COM 		/*
6127675SEdward.Pilatowicz@Sun.COM 		 * Check if this is a native object.  A native object is an
6137675SEdward.Pilatowicz@Sun.COM 		 * object from the global zone that is running in a branded
6147675SEdward.Pilatowicz@Sun.COM 		 * zone.  These objects are lofs mounted into a zone.  So if a
6157675SEdward.Pilatowicz@Sun.COM 		 * branded zone is not booted then lofs mounts won't be setup
6167675SEdward.Pilatowicz@Sun.COM 		 * so we won't be able to find these objects.  Luckily, we know
6177675SEdward.Pilatowicz@Sun.COM 		 * that they exist in the global zone with the same path sans
6187675SEdward.Pilatowicz@Sun.COM 		 * the initial native component, so we'll just strip out the
6197675SEdward.Pilatowicz@Sun.COM 		 * native component here.
6207675SEdward.Pilatowicz@Sun.COM 		 */
6217675SEdward.Pilatowicz@Sun.COM 		if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) ||
6227675SEdward.Pilatowicz@Sun.COM 		    (strncmp(zpath, "/.SUNWnative",
6237675SEdward.Pilatowicz@Sun.COM 		    sizeof ("/.SUNWnative")) == 0)) {
6247675SEdward.Pilatowicz@Sun.COM 
6257675SEdward.Pilatowicz@Sun.COM 			/* Free any cached symlink paths */
6267675SEdward.Pilatowicz@Sun.COM 			pn_free(&pn_links);
6277675SEdward.Pilatowicz@Sun.COM 
6287675SEdward.Pilatowicz@Sun.COM 			/* Reconstruct the path from our path component stack */
6297675SEdward.Pilatowicz@Sun.COM 			*zpath = '\0';
6307675SEdward.Pilatowicz@Sun.COM 			while (pn_pop(&pn_stack, tmp) != NULL) {
6317675SEdward.Pilatowicz@Sun.COM 				(void) strlcat(zpath, "/", sizeof (zpath));
6327675SEdward.Pilatowicz@Sun.COM 				(void) strlcat(zpath, tmp, sizeof (zpath));
6337675SEdward.Pilatowicz@Sun.COM 			}
6347675SEdward.Pilatowicz@Sun.COM 
6357675SEdward.Pilatowicz@Sun.COM 			/* Verify that the path actually exists */
6367675SEdward.Pilatowicz@Sun.COM 			rv = resolvepath(zpath, tmp, sizeof (tmp) - 1);
6377675SEdward.Pilatowicz@Sun.COM 			if (rv < 0) {
6387675SEdward.Pilatowicz@Sun.COM 				dprintf("Pzonepath invalid native path '%s'\n",
6397675SEdward.Pilatowicz@Sun.COM 				    zpath);
6407675SEdward.Pilatowicz@Sun.COM 				return (NULL);
6417675SEdward.Pilatowicz@Sun.COM 			}
6427675SEdward.Pilatowicz@Sun.COM 			tmp[rv] = '\0';
6437675SEdward.Pilatowicz@Sun.COM 
6447675SEdward.Pilatowicz@Sun.COM 			/* Return the path */
6457675SEdward.Pilatowicz@Sun.COM 			dprintf("Pzonepath found native path '%s'\n", tmp);
6467675SEdward.Pilatowicz@Sun.COM 			(void) Plofspath(tmp, tmp, sizeof (tmp));
6477675SEdward.Pilatowicz@Sun.COM 			(void) strlcpy(s, tmp, n);
6487675SEdward.Pilatowicz@Sun.COM 			return (s);
6497675SEdward.Pilatowicz@Sun.COM 		}
6507675SEdward.Pilatowicz@Sun.COM 
6517675SEdward.Pilatowicz@Sun.COM 		/*
6527675SEdward.Pilatowicz@Sun.COM 		 * Check if the path points to a symlink.  We do this
6537675SEdward.Pilatowicz@Sun.COM 		 * explicitly since any absolute symlink needs to be
6547675SEdward.Pilatowicz@Sun.COM 		 * interpreted relativly to the zone root and not "/".
6557675SEdward.Pilatowicz@Sun.COM 		 */
6567675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(tmp, zroot, sizeof (tmp));
6577675SEdward.Pilatowicz@Sun.COM 		(void) strlcat(tmp, zpath, sizeof (tmp));
6587675SEdward.Pilatowicz@Sun.COM 		if (lstat64(tmp, &sb) != 0) {
6597675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
6607675SEdward.Pilatowicz@Sun.COM 			return (NULL);
6617675SEdward.Pilatowicz@Sun.COM 		}
6627675SEdward.Pilatowicz@Sun.COM 		if (!S_ISLNK(sb.st_mode)) {
6637675SEdward.Pilatowicz@Sun.COM 			/*
6647675SEdward.Pilatowicz@Sun.COM 			 * Since the lstat64() above succeeded we know that
6657675SEdward.Pilatowicz@Sun.COM 			 * zpath exists, since this is not a symlink loop
6667675SEdward.Pilatowicz@Sun.COM 			 * around and check the next path component.
6677675SEdward.Pilatowicz@Sun.COM 			 */
6687675SEdward.Pilatowicz@Sun.COM 			continue;
6697675SEdward.Pilatowicz@Sun.COM 		}
6707675SEdward.Pilatowicz@Sun.COM 
6717675SEdward.Pilatowicz@Sun.COM 		/*
6727675SEdward.Pilatowicz@Sun.COM 		 * Symlink allow for paths with loops.  Make sure
6737675SEdward.Pilatowicz@Sun.COM 		 * we're not stuck in a loop.
6747675SEdward.Pilatowicz@Sun.COM 		 */
6757675SEdward.Pilatowicz@Sun.COM 		for (pn = pn_links; pn != NULL; pn = pn->pn_next) {
6767675SEdward.Pilatowicz@Sun.COM 			if (strcmp(zpath, pn->pn_path) != 0)
6777675SEdward.Pilatowicz@Sun.COM 				continue;
6787675SEdward.Pilatowicz@Sun.COM 
6797675SEdward.Pilatowicz@Sun.COM 			/* We have a loop.  Fail. */
6807675SEdward.Pilatowicz@Sun.COM 			dprintf("Pzonepath symlink loop '%s'\n", zpath);
6817675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
6827675SEdward.Pilatowicz@Sun.COM 			return (NULL);
6837675SEdward.Pilatowicz@Sun.COM 		}
6847675SEdward.Pilatowicz@Sun.COM 
6857675SEdward.Pilatowicz@Sun.COM 		/* Save this symlink path for future loop checks */
6867675SEdward.Pilatowicz@Sun.COM 		if (pn_push(&pn_links, zpath) == NULL) {
6877675SEdward.Pilatowicz@Sun.COM 			/* Out of memory */
6887675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
6897675SEdward.Pilatowicz@Sun.COM 			return (NULL);
6907675SEdward.Pilatowicz@Sun.COM 		}
6917675SEdward.Pilatowicz@Sun.COM 
6927675SEdward.Pilatowicz@Sun.COM 		/* Now follow the contents of the symlink */
6937675SEdward.Pilatowicz@Sun.COM 		bzero(link, sizeof (link));
6947675SEdward.Pilatowicz@Sun.COM 		if (readlink(tmp, link, sizeof (link)) == -1) {
6957675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
6967675SEdward.Pilatowicz@Sun.COM 			return (NULL);
6977675SEdward.Pilatowicz@Sun.COM 		}
6987675SEdward.Pilatowicz@Sun.COM 
6997675SEdward.Pilatowicz@Sun.COM 		dprintf("Pzonepath following symlink '%s' -> '%s'\n",
7007675SEdward.Pilatowicz@Sun.COM 		    zpath, link);
7017675SEdward.Pilatowicz@Sun.COM 
7027675SEdward.Pilatowicz@Sun.COM 		/*
7037675SEdward.Pilatowicz@Sun.COM 		 * Push each path component of the symlink target onto our
7047675SEdward.Pilatowicz@Sun.COM 		 * path components stack since we need to verify each one.
7057675SEdward.Pilatowicz@Sun.COM 		 */
7067675SEdward.Pilatowicz@Sun.COM 		while ((p = strrchr(link, '/')) != NULL) {
7077675SEdward.Pilatowicz@Sun.COM 			*p = '\0';
7087675SEdward.Pilatowicz@Sun.COM 			if (pn_push(&pn_stack, &p[1]) != NULL)
7097675SEdward.Pilatowicz@Sun.COM 				continue;
7107675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
7117675SEdward.Pilatowicz@Sun.COM 			return (NULL);
7127675SEdward.Pilatowicz@Sun.COM 		}
7137675SEdward.Pilatowicz@Sun.COM 
7147675SEdward.Pilatowicz@Sun.COM 		/* absolute or relative symlink? */
7157675SEdward.Pilatowicz@Sun.COM 		if (*link == '\0') {
7167675SEdward.Pilatowicz@Sun.COM 			/* Absolute symlink, nuke existing zpath. */
7177675SEdward.Pilatowicz@Sun.COM 			*zpath = '\0';
7187675SEdward.Pilatowicz@Sun.COM 			continue;
7197675SEdward.Pilatowicz@Sun.COM 		}
7207675SEdward.Pilatowicz@Sun.COM 
7217675SEdward.Pilatowicz@Sun.COM 		/*
7227675SEdward.Pilatowicz@Sun.COM 		 * Relative symlink.  Push the first path component of the
7237675SEdward.Pilatowicz@Sun.COM 		 * symlink target onto our stack for verification and then
7247675SEdward.Pilatowicz@Sun.COM 		 * remove the current path component from zpath.
7257675SEdward.Pilatowicz@Sun.COM 		 */
7267675SEdward.Pilatowicz@Sun.COM 		if (pn_push(&pn_stack, link) == NULL) {
7277675SEdward.Pilatowicz@Sun.COM 			pn_free2(&pn_stack, &pn_links);
7287675SEdward.Pilatowicz@Sun.COM 			return (NULL);
7297675SEdward.Pilatowicz@Sun.COM 		}
7307675SEdward.Pilatowicz@Sun.COM 		p = strrchr(zpath, '/');
7317675SEdward.Pilatowicz@Sun.COM 		assert(p != NULL);
7327675SEdward.Pilatowicz@Sun.COM 		*p = '\0';
7337675SEdward.Pilatowicz@Sun.COM 		continue;
7347675SEdward.Pilatowicz@Sun.COM 	}
7357675SEdward.Pilatowicz@Sun.COM 	pn_free(&pn_links);
7367675SEdward.Pilatowicz@Sun.COM 
7377675SEdward.Pilatowicz@Sun.COM 	/* Place the final result in zpath */
7387675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(tmp, zroot, sizeof (tmp));
7397675SEdward.Pilatowicz@Sun.COM 	(void) strlcat(tmp, zpath, sizeof (tmp));
7407675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(zpath, tmp, sizeof (zpath));
7417675SEdward.Pilatowicz@Sun.COM 
7427675SEdward.Pilatowicz@Sun.COM 	(void) Plofspath(zpath, zpath, sizeof (zpath));
7437675SEdward.Pilatowicz@Sun.COM 	dprintf("Pzonepath found zone path (3) '%s'\n", zpath);
7447675SEdward.Pilatowicz@Sun.COM 
7457675SEdward.Pilatowicz@Sun.COM 	(void) strlcpy(s, zpath, n);
7467675SEdward.Pilatowicz@Sun.COM 	return (s);
7477675SEdward.Pilatowicz@Sun.COM }
7487675SEdward.Pilatowicz@Sun.COM 
7497675SEdward.Pilatowicz@Sun.COM char *
Pfindobj(struct ps_prochandle * P,const char * path,char * s,size_t n)7507675SEdward.Pilatowicz@Sun.COM Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n)
7517675SEdward.Pilatowicz@Sun.COM {
7527675SEdward.Pilatowicz@Sun.COM 	int len;
7537675SEdward.Pilatowicz@Sun.COM 
7547675SEdward.Pilatowicz@Sun.COM 	dprintf("Pfindobj '%s'\n", path);
7557675SEdward.Pilatowicz@Sun.COM 
7567675SEdward.Pilatowicz@Sun.COM 	/* We only deal with absolute paths */
7577675SEdward.Pilatowicz@Sun.COM 	if (path[0] != '/')
7587675SEdward.Pilatowicz@Sun.COM 		return (NULL);
7597675SEdward.Pilatowicz@Sun.COM 
7607675SEdward.Pilatowicz@Sun.COM 	/* First try to resolve the path to some zone */
7617675SEdward.Pilatowicz@Sun.COM 	if (Pzonepath(P, path, s, n) != NULL)
7627675SEdward.Pilatowicz@Sun.COM 		return (s);
7637675SEdward.Pilatowicz@Sun.COM 
7647675SEdward.Pilatowicz@Sun.COM 	/* If that fails resolve any lofs links in the path */
7657675SEdward.Pilatowicz@Sun.COM 	if (Plofspath(path, s, n) != NULL)
7667675SEdward.Pilatowicz@Sun.COM 		return (s);
7677675SEdward.Pilatowicz@Sun.COM 
7687675SEdward.Pilatowicz@Sun.COM 	/* If that fails then just see if the path exists */
7697675SEdward.Pilatowicz@Sun.COM 	if ((len = resolvepath(path, s, n)) > 0) {
7707675SEdward.Pilatowicz@Sun.COM 		s[len] = '\0';
7717675SEdward.Pilatowicz@Sun.COM 		return (s);
7727675SEdward.Pilatowicz@Sun.COM 	}
7737675SEdward.Pilatowicz@Sun.COM 
7747675SEdward.Pilatowicz@Sun.COM 	return (NULL);
7757675SEdward.Pilatowicz@Sun.COM }
7767675SEdward.Pilatowicz@Sun.COM 
7777675SEdward.Pilatowicz@Sun.COM char *
Pfindmap(struct ps_prochandle * P,map_info_t * mptr,char * s,size_t n)7787675SEdward.Pilatowicz@Sun.COM Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n)
7797675SEdward.Pilatowicz@Sun.COM {
7807675SEdward.Pilatowicz@Sun.COM 	file_info_t *fptr = mptr->map_file;
7817675SEdward.Pilatowicz@Sun.COM 	char buf[PATH_MAX];
7827675SEdward.Pilatowicz@Sun.COM 	int len;
7837675SEdward.Pilatowicz@Sun.COM 
7847675SEdward.Pilatowicz@Sun.COM 	/* If it's already been explicity set return that */
7857675SEdward.Pilatowicz@Sun.COM 	if ((fptr != NULL) && (fptr->file_rname != NULL)) {
7867675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, fptr->file_rname, n);
7877675SEdward.Pilatowicz@Sun.COM 		return (s);
7887675SEdward.Pilatowicz@Sun.COM 	}
7897675SEdward.Pilatowicz@Sun.COM 
7907675SEdward.Pilatowicz@Sun.COM 	/* If it's the a.out segment, defer to the magical Pexecname() */
7917675SEdward.Pilatowicz@Sun.COM 	if ((P->map_exec == mptr) ||
7927675SEdward.Pilatowicz@Sun.COM 	    (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) ||
7937675SEdward.Pilatowicz@Sun.COM 	    ((fptr != NULL) && (fptr->file_lname != NULL) &&
7947675SEdward.Pilatowicz@Sun.COM 	    (strcmp(fptr->file_lname, "a.out") == 0))) {
7957675SEdward.Pilatowicz@Sun.COM 		(void) Pexecname(P, buf, sizeof (buf));
7967675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, buf, n);
7977675SEdward.Pilatowicz@Sun.COM 		return (s);
7987675SEdward.Pilatowicz@Sun.COM 	}
7997675SEdward.Pilatowicz@Sun.COM 
8007675SEdward.Pilatowicz@Sun.COM 	/* Try /proc first to get the real object name */
8017675SEdward.Pilatowicz@Sun.COM 	if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) {
8027675SEdward.Pilatowicz@Sun.COM 		(void) snprintf(buf, sizeof (buf), "%s/%d/path/%s",
8037675SEdward.Pilatowicz@Sun.COM 		    procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname);
8047675SEdward.Pilatowicz@Sun.COM 		if ((len = readlink(buf, buf, sizeof (buf))) > 0) {
8057675SEdward.Pilatowicz@Sun.COM 			buf[len] = '\0';
8067675SEdward.Pilatowicz@Sun.COM 			(void) Plofspath(buf, buf, sizeof (buf));
8077675SEdward.Pilatowicz@Sun.COM 			(void) strlcpy(s, buf, n);
8087675SEdward.Pilatowicz@Sun.COM 			return (s);
8097675SEdward.Pilatowicz@Sun.COM 		}
8107675SEdward.Pilatowicz@Sun.COM 	}
8117675SEdward.Pilatowicz@Sun.COM 
8127675SEdward.Pilatowicz@Sun.COM 	/*
8137675SEdward.Pilatowicz@Sun.COM 	 * If we couldn't get the name from /proc, take the lname and
8147675SEdward.Pilatowicz@Sun.COM 	 * try to expand it on the current system to a real object path.
8157675SEdward.Pilatowicz@Sun.COM 	 */
8167675SEdward.Pilatowicz@Sun.COM 	fptr = mptr->map_file;
8177675SEdward.Pilatowicz@Sun.COM 	if ((fptr != NULL) && (fptr->file_lname != NULL)) {
8187675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(buf, fptr->file_lname, sizeof (buf));
8197675SEdward.Pilatowicz@Sun.COM 		if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL)
8207675SEdward.Pilatowicz@Sun.COM 			return (NULL);
8217675SEdward.Pilatowicz@Sun.COM 		(void) strlcpy(s, buf, n);
8227675SEdward.Pilatowicz@Sun.COM 		return (s);
8237675SEdward.Pilatowicz@Sun.COM 	}
8247675SEdward.Pilatowicz@Sun.COM 
8257675SEdward.Pilatowicz@Sun.COM 	return (NULL);
8267675SEdward.Pilatowicz@Sun.COM }
827