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