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