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