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