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. 28*2a12f85aSJeremy 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 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 * 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 * 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 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 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 * 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 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 * 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 * 233186f7fbfSEdward Pilatowicz Pzonename(struct ps_prochandle *P, char *s, size_t n) 234186f7fbfSEdward Pilatowicz { 235*2a12f85aSJeremy Jones return (P->ops.pop_zonename(P, s, n, P->data)); 236186f7fbfSEdward Pilatowicz } 237186f7fbfSEdward Pilatowicz 238186f7fbfSEdward Pilatowicz char * 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 * 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. 390186f7fbfSEdward Pilatowicz */ 391a7e1d0d3SRoger A. Faulkner (void) strlcpy(tmp2, special, sizeof (tmp2) - 1); 392186f7fbfSEdward Pilatowicz (void) strlcat(tmp2, "/", sizeof (tmp2) - 1); 393186f7fbfSEdward Pilatowicz (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1); 394186f7fbfSEdward Pilatowicz (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1); 395186f7fbfSEdward Pilatowicz if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 396186f7fbfSEdward Pilatowicz tmp[rv] = '\0'; 397186f7fbfSEdward Pilatowicz p = &tmp[strlen(tmp)]; 398186f7fbfSEdward Pilatowicz p[1] = '\0'; 399186f7fbfSEdward Pilatowicz continue; 400186f7fbfSEdward Pilatowicz } 401186f7fbfSEdward Pilatowicz 402186f7fbfSEdward Pilatowicz /* No lofs mount found */ 403186f7fbfSEdward Pilatowicz if ((p2 = strrchr(tmp, '/')) == NULL) { 404186f7fbfSEdward Pilatowicz char tmp2[PATH_MAX]; 405186f7fbfSEdward Pilatowicz 406a7e1d0d3SRoger A. Faulkner (void) mutex_unlock(&lofs_lock); 407a7e1d0d3SRoger A. Faulkner 408186f7fbfSEdward Pilatowicz /* 409186f7fbfSEdward Pilatowicz * We know that tmp was an absolute path, so if we 410186f7fbfSEdward Pilatowicz * made it here we know that (p == tmp) and that 411186f7fbfSEdward Pilatowicz * (*p == '\0'). This means that we've managed 412186f7fbfSEdward Pilatowicz * to check the whole path and so we're done. 413186f7fbfSEdward Pilatowicz */ 414186f7fbfSEdward Pilatowicz assert(p == tmp); 415186f7fbfSEdward Pilatowicz assert(p[0] == '\0'); 416186f7fbfSEdward Pilatowicz 417186f7fbfSEdward Pilatowicz /* Restore the leading '/' in the path */ 418186f7fbfSEdward Pilatowicz p[0] = '/'; 419186f7fbfSEdward Pilatowicz 420186f7fbfSEdward Pilatowicz if (strcmp(tmp, path) == 0) { 421186f7fbfSEdward Pilatowicz /* The path didn't change */ 422186f7fbfSEdward Pilatowicz return (NULL); 423186f7fbfSEdward Pilatowicz } 424186f7fbfSEdward Pilatowicz 425186f7fbfSEdward Pilatowicz /* 426186f7fbfSEdward Pilatowicz * It's possible that lofs source path we just 427186f7fbfSEdward Pilatowicz * obtained contains a symbolic link. Use 428186f7fbfSEdward Pilatowicz * resolvepath() to clean it up. 429186f7fbfSEdward Pilatowicz */ 430186f7fbfSEdward Pilatowicz (void) strlcpy(tmp2, tmp, sizeof (tmp2)); 431186f7fbfSEdward Pilatowicz if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 432186f7fbfSEdward Pilatowicz tmp[rv] = '\0'; 433186f7fbfSEdward Pilatowicz 434186f7fbfSEdward Pilatowicz /* 435186f7fbfSEdward Pilatowicz * It's always possible that our lofs source path is 436186f7fbfSEdward Pilatowicz * actually another lofs mount. So call ourselves 437186f7fbfSEdward Pilatowicz * recursively to resolve that path. 438186f7fbfSEdward Pilatowicz */ 439186f7fbfSEdward Pilatowicz (void) Plofspath(tmp, tmp, PATH_MAX); 440186f7fbfSEdward Pilatowicz 441186f7fbfSEdward Pilatowicz /* Copy out our final resolved lofs source path */ 442186f7fbfSEdward Pilatowicz (void) strlcpy(s, tmp, n); 443186f7fbfSEdward Pilatowicz dprintf("Plofspath path result '%s'\n", s); 444186f7fbfSEdward Pilatowicz return (s); 445186f7fbfSEdward Pilatowicz } 446186f7fbfSEdward Pilatowicz 447186f7fbfSEdward Pilatowicz /* 448186f7fbfSEdward Pilatowicz * So the path we just checked is not a lofs mount. Next we 449186f7fbfSEdward Pilatowicz * want to check the parent path component for a lofs mount. 450186f7fbfSEdward Pilatowicz * 451186f7fbfSEdward Pilatowicz * First, restore any '/' that we replaced with a '\0' (NUL). 452186f7fbfSEdward Pilatowicz * We can determine if we should do this by looking at p[1]. 453186f7fbfSEdward Pilatowicz * If p[1] points to a '\0' (NUL) then we know that p points 454186f7fbfSEdward Pilatowicz * to the end of the string and there is no '/' to restore. 455186f7fbfSEdward Pilatowicz * if p[1] doesn't point to a '\0' (NUL) then it points to 456186f7fbfSEdward Pilatowicz * the part of the path that we've already verified so there 457186f7fbfSEdward Pilatowicz * is a '/' to restore. 458186f7fbfSEdward Pilatowicz */ 459186f7fbfSEdward Pilatowicz if (p[1] != '\0') 460186f7fbfSEdward Pilatowicz p[0] = '/'; 461186f7fbfSEdward Pilatowicz 462186f7fbfSEdward Pilatowicz /* 463186f7fbfSEdward Pilatowicz * Second, replace the last '/' in the part of the path 464186f7fbfSEdward Pilatowicz * that we've already checked with a '\0' (NUL) so that 465186f7fbfSEdward Pilatowicz * when we loop around we check the parent component of the 466186f7fbfSEdward Pilatowicz * path. 467186f7fbfSEdward Pilatowicz */ 468186f7fbfSEdward Pilatowicz p2[0] = '\0'; 469186f7fbfSEdward Pilatowicz p = p2; 470186f7fbfSEdward Pilatowicz } 471186f7fbfSEdward Pilatowicz /*NOTREACHED*/ 472186f7fbfSEdward Pilatowicz } 473186f7fbfSEdward Pilatowicz 474186f7fbfSEdward Pilatowicz /* 475186f7fbfSEdward Pilatowicz * Pzonepath() - Way too much code to attempt to derive the full path of 476186f7fbfSEdward Pilatowicz * an object within a zone. 477186f7fbfSEdward Pilatowicz * 478186f7fbfSEdward Pilatowicz * Pzonepath() takes a path and attempts to resolve it relative to the 479186f7fbfSEdward Pilatowicz * root associated with the current process handle. If it fails it will 480186f7fbfSEdward Pilatowicz * not update the results string. It is safe to specify the same pointer 481186f7fbfSEdward Pilatowicz * for the file string and the results string. 482186f7fbfSEdward Pilatowicz * 483186f7fbfSEdward Pilatowicz * Doing this resolution is more difficult than it initially sounds. 484186f7fbfSEdward Pilatowicz * We can't simply append the file path to the zone root, because in 485186f7fbfSEdward Pilatowicz * a root directory, '..' is treated the same as '.'. Also, symbolic 486186f7fbfSEdward Pilatowicz * links that specify an absolute path need to be interpreted relative 487186f7fbfSEdward Pilatowicz * to the zone root. 488186f7fbfSEdward Pilatowicz * 489186f7fbfSEdward Pilatowicz * It seems like perhaps we could do a chroot(<zone root>) followed by a 490186f7fbfSEdward Pilatowicz * resolvepath(). But we can't do this because chroot requires special 491186f7fbfSEdward Pilatowicz * privileges and affects the entire process. Perhaps if there was a 492186f7fbfSEdward Pilatowicz * special version of resolvepath() which took an addition root path 493186f7fbfSEdward Pilatowicz * we could use that, but this isn't ideal either. The reason is 494186f7fbfSEdward Pilatowicz * that we want to have special handling for native paths. (A native path 495186f7fbfSEdward Pilatowicz * is a path that begins with "/native/" or "/.SUNWnative/".) Native 496186f7fbfSEdward Pilatowicz * paths could be passed explicity to this function or could be embedded 497186f7fbfSEdward Pilatowicz * in a symlink that is part of the path passed into this function. 498186f7fbfSEdward Pilatowicz * These paths are always lofs mounts of global zone paths, but lofs 499186f7fbfSEdward Pilatowicz * mounts only exist when a zone is booted. So if we were to try to do 500186f7fbfSEdward Pilatowicz * a resolvepath() on a native path when the zone wasn't booted the 501186f7fbfSEdward Pilatowicz * resolvepath() would fail even though we know that the components 502186f7fbfSEdward Pilatowicz * exists in the global zone. 503186f7fbfSEdward Pilatowicz * 504186f7fbfSEdward Pilatowicz * Given all these constraints, we just implement a path walking function 505186f7fbfSEdward Pilatowicz * that resolves a file path relative to a zone root by manually inspecting 506186f7fbfSEdward Pilatowicz * each of the path components and verifying its existence. This means that 507186f7fbfSEdward Pilatowicz * we must have access to the zone and that all the components of the 508186f7fbfSEdward Pilatowicz * path must exist for this operation to succeed. 509186f7fbfSEdward Pilatowicz */ 510186f7fbfSEdward Pilatowicz char * 511186f7fbfSEdward Pilatowicz Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n) 512186f7fbfSEdward Pilatowicz { 513186f7fbfSEdward Pilatowicz char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX]; 514186f7fbfSEdward Pilatowicz path_node_t *pn_stack = NULL, *pn_links = NULL, *pn; 515186f7fbfSEdward Pilatowicz struct stat64 sb; 516186f7fbfSEdward Pilatowicz char *p; 517186f7fbfSEdward Pilatowicz int i, rv; 518186f7fbfSEdward Pilatowicz 519186f7fbfSEdward Pilatowicz dprintf("Pzonepath lookup '%s'\n", path); 520186f7fbfSEdward Pilatowicz 521186f7fbfSEdward Pilatowicz /* First lookup the zone root */ 522186f7fbfSEdward Pilatowicz if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL) 523186f7fbfSEdward Pilatowicz return (NULL); 524186f7fbfSEdward Pilatowicz 525186f7fbfSEdward Pilatowicz /* 526186f7fbfSEdward Pilatowicz * Make a temporary copy of the path specified. 527186f7fbfSEdward Pilatowicz * If it's a relative path then make it into an absolute path. 528186f7fbfSEdward Pilatowicz */ 529186f7fbfSEdward Pilatowicz tmp[0] = '\0'; 530186f7fbfSEdward Pilatowicz if (path[0] != '/') 531186f7fbfSEdward Pilatowicz (void) strlcat(tmp, "/", sizeof (tmp)); 532186f7fbfSEdward Pilatowicz (void) strlcat(tmp, path, sizeof (tmp)); 533186f7fbfSEdward Pilatowicz 534186f7fbfSEdward Pilatowicz /* 535186f7fbfSEdward Pilatowicz * If the path that was passed in is the zone root, we're done. 536186f7fbfSEdward Pilatowicz * If the path that was passed in already contains the zone root 537186f7fbfSEdward Pilatowicz * then strip the zone root out and verify the rest of the path. 538186f7fbfSEdward Pilatowicz */ 539186f7fbfSEdward Pilatowicz if (strcmp(tmp, zroot) == 0) { 540186f7fbfSEdward Pilatowicz (void) Plofspath(zroot, zroot, sizeof (zroot)); 541186f7fbfSEdward Pilatowicz dprintf("Pzonepath found zone path (1) '%s'\n", zroot); 542186f7fbfSEdward Pilatowicz (void) strlcpy(s, zroot, n); 543186f7fbfSEdward Pilatowicz return (s); 544186f7fbfSEdward Pilatowicz } 545186f7fbfSEdward Pilatowicz i = strlen(zroot); 546186f7fbfSEdward Pilatowicz if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/')) 547186f7fbfSEdward Pilatowicz (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1); 548186f7fbfSEdward Pilatowicz 549186f7fbfSEdward Pilatowicz /* If no path is passed in, then it maps to the zone root */ 550186f7fbfSEdward Pilatowicz if (strlen(tmp) == 0) { 551186f7fbfSEdward Pilatowicz (void) Plofspath(zroot, zroot, sizeof (zroot)); 552186f7fbfSEdward Pilatowicz dprintf("Pzonepath found zone path (2) '%s'\n", zroot); 553186f7fbfSEdward Pilatowicz (void) strlcpy(s, zroot, n); 554186f7fbfSEdward Pilatowicz return (s); 555186f7fbfSEdward Pilatowicz } 556186f7fbfSEdward Pilatowicz 557186f7fbfSEdward Pilatowicz /* 558186f7fbfSEdward Pilatowicz * Push each path component that we plan to verify onto a stack of 559186f7fbfSEdward Pilatowicz * path components, with parent components at the top of the stack. 560186f7fbfSEdward Pilatowicz * So for example, if we're going to verify the path /foo/bar/bang 561186f7fbfSEdward Pilatowicz * then our stack will look like: 562186f7fbfSEdward Pilatowicz * foo (top) 563186f7fbfSEdward Pilatowicz * bar 564186f7fbfSEdward Pilatowicz * bang (bottom) 565186f7fbfSEdward Pilatowicz */ 566186f7fbfSEdward Pilatowicz while ((p = strrchr(tmp, '/')) != NULL) { 567186f7fbfSEdward Pilatowicz *p = '\0'; 568186f7fbfSEdward Pilatowicz if (pn_push(&pn_stack, &p[1]) != NULL) 569186f7fbfSEdward Pilatowicz continue; 570186f7fbfSEdward Pilatowicz pn_free(&pn_stack); 571186f7fbfSEdward Pilatowicz return (NULL); 572186f7fbfSEdward Pilatowicz } 573186f7fbfSEdward Pilatowicz 574186f7fbfSEdward Pilatowicz /* We're going to store the final zone relative path in zpath */ 575186f7fbfSEdward Pilatowicz *zpath = '\0'; 576186f7fbfSEdward Pilatowicz 577186f7fbfSEdward Pilatowicz while (pn_pop(&pn_stack, tmp) != NULL) { 578186f7fbfSEdward Pilatowicz /* 579186f7fbfSEdward Pilatowicz * Drop zero length path components (which come from 580186f7fbfSEdward Pilatowicz * consecutive '/'s) and '.' path components. 581186f7fbfSEdward Pilatowicz */ 582186f7fbfSEdward Pilatowicz if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0)) 583186f7fbfSEdward Pilatowicz continue; 584186f7fbfSEdward Pilatowicz 585186f7fbfSEdward Pilatowicz /* 586186f7fbfSEdward Pilatowicz * Check the current path component for '..', if found 587186f7fbfSEdward Pilatowicz * drop any previous path component. 588186f7fbfSEdward Pilatowicz */ 589186f7fbfSEdward Pilatowicz if (strcmp(tmp, "..") == 0) { 590186f7fbfSEdward Pilatowicz if ((p = strrchr(zpath, '/')) != NULL) 591186f7fbfSEdward Pilatowicz *p = '\0'; 592186f7fbfSEdward Pilatowicz continue; 593186f7fbfSEdward Pilatowicz } 594186f7fbfSEdward Pilatowicz 595186f7fbfSEdward Pilatowicz /* The path we want to verify now is zpath + / + tmp. */ 596186f7fbfSEdward Pilatowicz (void) strlcat(zpath, "/", sizeof (zpath)); 597186f7fbfSEdward Pilatowicz (void) strlcat(zpath, tmp, sizeof (zpath)); 598186f7fbfSEdward Pilatowicz 599186f7fbfSEdward Pilatowicz /* 600186f7fbfSEdward Pilatowicz * Check if this is a native object. A native object is an 601186f7fbfSEdward Pilatowicz * object from the global zone that is running in a branded 602186f7fbfSEdward Pilatowicz * zone. These objects are lofs mounted into a zone. So if a 603186f7fbfSEdward Pilatowicz * branded zone is not booted then lofs mounts won't be setup 604186f7fbfSEdward Pilatowicz * so we won't be able to find these objects. Luckily, we know 605186f7fbfSEdward Pilatowicz * that they exist in the global zone with the same path sans 606186f7fbfSEdward Pilatowicz * the initial native component, so we'll just strip out the 607186f7fbfSEdward Pilatowicz * native component here. 608186f7fbfSEdward Pilatowicz */ 609186f7fbfSEdward Pilatowicz if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) || 610186f7fbfSEdward Pilatowicz (strncmp(zpath, "/.SUNWnative", 611186f7fbfSEdward Pilatowicz sizeof ("/.SUNWnative")) == 0)) { 612186f7fbfSEdward Pilatowicz 613186f7fbfSEdward Pilatowicz /* Free any cached symlink paths */ 614186f7fbfSEdward Pilatowicz pn_free(&pn_links); 615186f7fbfSEdward Pilatowicz 616186f7fbfSEdward Pilatowicz /* Reconstruct the path from our path component stack */ 617186f7fbfSEdward Pilatowicz *zpath = '\0'; 618186f7fbfSEdward Pilatowicz while (pn_pop(&pn_stack, tmp) != NULL) { 619186f7fbfSEdward Pilatowicz (void) strlcat(zpath, "/", sizeof (zpath)); 620186f7fbfSEdward Pilatowicz (void) strlcat(zpath, tmp, sizeof (zpath)); 621186f7fbfSEdward Pilatowicz } 622186f7fbfSEdward Pilatowicz 623186f7fbfSEdward Pilatowicz /* Verify that the path actually exists */ 624186f7fbfSEdward Pilatowicz rv = resolvepath(zpath, tmp, sizeof (tmp) - 1); 625186f7fbfSEdward Pilatowicz if (rv < 0) { 626186f7fbfSEdward Pilatowicz dprintf("Pzonepath invalid native path '%s'\n", 627186f7fbfSEdward Pilatowicz zpath); 628186f7fbfSEdward Pilatowicz return (NULL); 629186f7fbfSEdward Pilatowicz } 630186f7fbfSEdward Pilatowicz tmp[rv] = '\0'; 631186f7fbfSEdward Pilatowicz 632186f7fbfSEdward Pilatowicz /* Return the path */ 633186f7fbfSEdward Pilatowicz dprintf("Pzonepath found native path '%s'\n", tmp); 634186f7fbfSEdward Pilatowicz (void) Plofspath(tmp, tmp, sizeof (tmp)); 635186f7fbfSEdward Pilatowicz (void) strlcpy(s, tmp, n); 636186f7fbfSEdward Pilatowicz return (s); 637186f7fbfSEdward Pilatowicz } 638186f7fbfSEdward Pilatowicz 639186f7fbfSEdward Pilatowicz /* 640186f7fbfSEdward Pilatowicz * Check if the path points to a symlink. We do this 641186f7fbfSEdward Pilatowicz * explicitly since any absolute symlink needs to be 642186f7fbfSEdward Pilatowicz * interpreted relativly to the zone root and not "/". 643186f7fbfSEdward Pilatowicz */ 644186f7fbfSEdward Pilatowicz (void) strlcpy(tmp, zroot, sizeof (tmp)); 645186f7fbfSEdward Pilatowicz (void) strlcat(tmp, zpath, sizeof (tmp)); 646186f7fbfSEdward Pilatowicz if (lstat64(tmp, &sb) != 0) { 647186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 648186f7fbfSEdward Pilatowicz return (NULL); 649186f7fbfSEdward Pilatowicz } 650186f7fbfSEdward Pilatowicz if (!S_ISLNK(sb.st_mode)) { 651186f7fbfSEdward Pilatowicz /* 652186f7fbfSEdward Pilatowicz * Since the lstat64() above succeeded we know that 653186f7fbfSEdward Pilatowicz * zpath exists, since this is not a symlink loop 654186f7fbfSEdward Pilatowicz * around and check the next path component. 655186f7fbfSEdward Pilatowicz */ 656186f7fbfSEdward Pilatowicz continue; 657186f7fbfSEdward Pilatowicz } 658186f7fbfSEdward Pilatowicz 659186f7fbfSEdward Pilatowicz /* 660186f7fbfSEdward Pilatowicz * Symlink allow for paths with loops. Make sure 661186f7fbfSEdward Pilatowicz * we're not stuck in a loop. 662186f7fbfSEdward Pilatowicz */ 663186f7fbfSEdward Pilatowicz for (pn = pn_links; pn != NULL; pn = pn->pn_next) { 664186f7fbfSEdward Pilatowicz if (strcmp(zpath, pn->pn_path) != 0) 665186f7fbfSEdward Pilatowicz continue; 666186f7fbfSEdward Pilatowicz 667186f7fbfSEdward Pilatowicz /* We have a loop. Fail. */ 668186f7fbfSEdward Pilatowicz dprintf("Pzonepath symlink loop '%s'\n", zpath); 669186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 670186f7fbfSEdward Pilatowicz return (NULL); 671186f7fbfSEdward Pilatowicz } 672186f7fbfSEdward Pilatowicz 673186f7fbfSEdward Pilatowicz /* Save this symlink path for future loop checks */ 674186f7fbfSEdward Pilatowicz if (pn_push(&pn_links, zpath) == NULL) { 675186f7fbfSEdward Pilatowicz /* Out of memory */ 676186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 677186f7fbfSEdward Pilatowicz return (NULL); 678186f7fbfSEdward Pilatowicz } 679186f7fbfSEdward Pilatowicz 680186f7fbfSEdward Pilatowicz /* Now follow the contents of the symlink */ 681186f7fbfSEdward Pilatowicz bzero(link, sizeof (link)); 682186f7fbfSEdward Pilatowicz if (readlink(tmp, link, sizeof (link)) == -1) { 683186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 684186f7fbfSEdward Pilatowicz return (NULL); 685186f7fbfSEdward Pilatowicz } 686186f7fbfSEdward Pilatowicz 687186f7fbfSEdward Pilatowicz dprintf("Pzonepath following symlink '%s' -> '%s'\n", 688186f7fbfSEdward Pilatowicz zpath, link); 689186f7fbfSEdward Pilatowicz 690186f7fbfSEdward Pilatowicz /* 691186f7fbfSEdward Pilatowicz * Push each path component of the symlink target onto our 692186f7fbfSEdward Pilatowicz * path components stack since we need to verify each one. 693186f7fbfSEdward Pilatowicz */ 694186f7fbfSEdward Pilatowicz while ((p = strrchr(link, '/')) != NULL) { 695186f7fbfSEdward Pilatowicz *p = '\0'; 696186f7fbfSEdward Pilatowicz if (pn_push(&pn_stack, &p[1]) != NULL) 697186f7fbfSEdward Pilatowicz continue; 698186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 699186f7fbfSEdward Pilatowicz return (NULL); 700186f7fbfSEdward Pilatowicz } 701186f7fbfSEdward Pilatowicz 702186f7fbfSEdward Pilatowicz /* absolute or relative symlink? */ 703186f7fbfSEdward Pilatowicz if (*link == '\0') { 704186f7fbfSEdward Pilatowicz /* Absolute symlink, nuke existing zpath. */ 705186f7fbfSEdward Pilatowicz *zpath = '\0'; 706186f7fbfSEdward Pilatowicz continue; 707186f7fbfSEdward Pilatowicz } 708186f7fbfSEdward Pilatowicz 709186f7fbfSEdward Pilatowicz /* 710186f7fbfSEdward Pilatowicz * Relative symlink. Push the first path component of the 711186f7fbfSEdward Pilatowicz * symlink target onto our stack for verification and then 712186f7fbfSEdward Pilatowicz * remove the current path component from zpath. 713186f7fbfSEdward Pilatowicz */ 714186f7fbfSEdward Pilatowicz if (pn_push(&pn_stack, link) == NULL) { 715186f7fbfSEdward Pilatowicz pn_free2(&pn_stack, &pn_links); 716186f7fbfSEdward Pilatowicz return (NULL); 717186f7fbfSEdward Pilatowicz } 718186f7fbfSEdward Pilatowicz p = strrchr(zpath, '/'); 719186f7fbfSEdward Pilatowicz assert(p != NULL); 720186f7fbfSEdward Pilatowicz *p = '\0'; 721186f7fbfSEdward Pilatowicz continue; 722186f7fbfSEdward Pilatowicz } 723186f7fbfSEdward Pilatowicz pn_free(&pn_links); 724186f7fbfSEdward Pilatowicz 725186f7fbfSEdward Pilatowicz /* Place the final result in zpath */ 726186f7fbfSEdward Pilatowicz (void) strlcpy(tmp, zroot, sizeof (tmp)); 727186f7fbfSEdward Pilatowicz (void) strlcat(tmp, zpath, sizeof (tmp)); 728186f7fbfSEdward Pilatowicz (void) strlcpy(zpath, tmp, sizeof (zpath)); 729186f7fbfSEdward Pilatowicz 730186f7fbfSEdward Pilatowicz (void) Plofspath(zpath, zpath, sizeof (zpath)); 731186f7fbfSEdward Pilatowicz dprintf("Pzonepath found zone path (3) '%s'\n", zpath); 732186f7fbfSEdward Pilatowicz 733186f7fbfSEdward Pilatowicz (void) strlcpy(s, zpath, n); 734186f7fbfSEdward Pilatowicz return (s); 735186f7fbfSEdward Pilatowicz } 736186f7fbfSEdward Pilatowicz 737186f7fbfSEdward Pilatowicz char * 738186f7fbfSEdward Pilatowicz Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n) 739186f7fbfSEdward Pilatowicz { 740186f7fbfSEdward Pilatowicz int len; 741186f7fbfSEdward Pilatowicz 742186f7fbfSEdward Pilatowicz dprintf("Pfindobj '%s'\n", path); 743186f7fbfSEdward Pilatowicz 744186f7fbfSEdward Pilatowicz /* We only deal with absolute paths */ 745186f7fbfSEdward Pilatowicz if (path[0] != '/') 746186f7fbfSEdward Pilatowicz return (NULL); 747186f7fbfSEdward Pilatowicz 748186f7fbfSEdward Pilatowicz /* First try to resolve the path to some zone */ 749186f7fbfSEdward Pilatowicz if (Pzonepath(P, path, s, n) != NULL) 750186f7fbfSEdward Pilatowicz return (s); 751186f7fbfSEdward Pilatowicz 752186f7fbfSEdward Pilatowicz /* If that fails resolve any lofs links in the path */ 753186f7fbfSEdward Pilatowicz if (Plofspath(path, s, n) != NULL) 754186f7fbfSEdward Pilatowicz return (s); 755186f7fbfSEdward Pilatowicz 756186f7fbfSEdward Pilatowicz /* If that fails then just see if the path exists */ 757186f7fbfSEdward Pilatowicz if ((len = resolvepath(path, s, n)) > 0) { 758186f7fbfSEdward Pilatowicz s[len] = '\0'; 759186f7fbfSEdward Pilatowicz return (s); 760186f7fbfSEdward Pilatowicz } 761186f7fbfSEdward Pilatowicz 762186f7fbfSEdward Pilatowicz return (NULL); 763186f7fbfSEdward Pilatowicz } 764186f7fbfSEdward Pilatowicz 765186f7fbfSEdward Pilatowicz char * 766186f7fbfSEdward Pilatowicz Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n) 767186f7fbfSEdward Pilatowicz { 768186f7fbfSEdward Pilatowicz file_info_t *fptr = mptr->map_file; 769186f7fbfSEdward Pilatowicz char buf[PATH_MAX]; 770186f7fbfSEdward Pilatowicz int len; 771186f7fbfSEdward Pilatowicz 772186f7fbfSEdward Pilatowicz /* If it's already been explicity set return that */ 773186f7fbfSEdward Pilatowicz if ((fptr != NULL) && (fptr->file_rname != NULL)) { 774186f7fbfSEdward Pilatowicz (void) strlcpy(s, fptr->file_rname, n); 775186f7fbfSEdward Pilatowicz return (s); 776186f7fbfSEdward Pilatowicz } 777186f7fbfSEdward Pilatowicz 778186f7fbfSEdward Pilatowicz /* If it's the a.out segment, defer to the magical Pexecname() */ 779186f7fbfSEdward Pilatowicz if ((P->map_exec == mptr) || 780186f7fbfSEdward Pilatowicz (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) || 781186f7fbfSEdward Pilatowicz ((fptr != NULL) && (fptr->file_lname != NULL) && 782186f7fbfSEdward Pilatowicz (strcmp(fptr->file_lname, "a.out") == 0))) { 7838f68126cSBryan Cantrill if (Pexecname(P, buf, sizeof (buf)) != NULL) { 784186f7fbfSEdward Pilatowicz (void) strlcpy(s, buf, n); 785186f7fbfSEdward Pilatowicz return (s); 786186f7fbfSEdward Pilatowicz } 7878f68126cSBryan Cantrill } 788186f7fbfSEdward Pilatowicz 789186f7fbfSEdward Pilatowicz /* Try /proc first to get the real object name */ 790186f7fbfSEdward Pilatowicz if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) { 791186f7fbfSEdward Pilatowicz (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s", 792186f7fbfSEdward Pilatowicz procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname); 793186f7fbfSEdward Pilatowicz if ((len = readlink(buf, buf, sizeof (buf))) > 0) { 794186f7fbfSEdward Pilatowicz buf[len] = '\0'; 795186f7fbfSEdward Pilatowicz (void) Plofspath(buf, buf, sizeof (buf)); 796186f7fbfSEdward Pilatowicz (void) strlcpy(s, buf, n); 797186f7fbfSEdward Pilatowicz return (s); 798186f7fbfSEdward Pilatowicz } 799186f7fbfSEdward Pilatowicz } 800186f7fbfSEdward Pilatowicz 801186f7fbfSEdward Pilatowicz /* 802186f7fbfSEdward Pilatowicz * If we couldn't get the name from /proc, take the lname and 803186f7fbfSEdward Pilatowicz * try to expand it on the current system to a real object path. 804186f7fbfSEdward Pilatowicz */ 805186f7fbfSEdward Pilatowicz fptr = mptr->map_file; 806186f7fbfSEdward Pilatowicz if ((fptr != NULL) && (fptr->file_lname != NULL)) { 807186f7fbfSEdward Pilatowicz (void) strlcpy(buf, fptr->file_lname, sizeof (buf)); 808186f7fbfSEdward Pilatowicz if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL) 809186f7fbfSEdward Pilatowicz return (NULL); 810186f7fbfSEdward Pilatowicz (void) strlcpy(s, buf, n); 811186f7fbfSEdward Pilatowicz return (s); 812186f7fbfSEdward Pilatowicz } 813186f7fbfSEdward Pilatowicz 814186f7fbfSEdward Pilatowicz return (NULL); 815186f7fbfSEdward Pilatowicz } 816