1*7675SEdward.Pilatowicz@Sun.COM /* 2*7675SEdward.Pilatowicz@Sun.COM * CDDL HEADER START 3*7675SEdward.Pilatowicz@Sun.COM * 4*7675SEdward.Pilatowicz@Sun.COM * The contents of this file are subject to the terms of the 5*7675SEdward.Pilatowicz@Sun.COM * Common Development and Distribution License (the "License"). 6*7675SEdward.Pilatowicz@Sun.COM * You may not use this file except in compliance with the License. 7*7675SEdward.Pilatowicz@Sun.COM * 8*7675SEdward.Pilatowicz@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7675SEdward.Pilatowicz@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*7675SEdward.Pilatowicz@Sun.COM * See the License for the specific language governing permissions 11*7675SEdward.Pilatowicz@Sun.COM * and limitations under the License. 12*7675SEdward.Pilatowicz@Sun.COM * 13*7675SEdward.Pilatowicz@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*7675SEdward.Pilatowicz@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7675SEdward.Pilatowicz@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*7675SEdward.Pilatowicz@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*7675SEdward.Pilatowicz@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*7675SEdward.Pilatowicz@Sun.COM * 19*7675SEdward.Pilatowicz@Sun.COM * CDDL HEADER END 20*7675SEdward.Pilatowicz@Sun.COM */ 21*7675SEdward.Pilatowicz@Sun.COM 22*7675SEdward.Pilatowicz@Sun.COM /* 23*7675SEdward.Pilatowicz@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*7675SEdward.Pilatowicz@Sun.COM * Use is subject to license terms. 25*7675SEdward.Pilatowicz@Sun.COM */ 26*7675SEdward.Pilatowicz@Sun.COM 27*7675SEdward.Pilatowicz@Sun.COM #include <assert.h> 28*7675SEdward.Pilatowicz@Sun.COM #include <dlfcn.h> 29*7675SEdward.Pilatowicz@Sun.COM #include <errno.h> 30*7675SEdward.Pilatowicz@Sun.COM #include <libzonecfg.h> 31*7675SEdward.Pilatowicz@Sun.COM #include <link.h> 32*7675SEdward.Pilatowicz@Sun.COM #include <string.h> 33*7675SEdward.Pilatowicz@Sun.COM #include <strings.h> 34*7675SEdward.Pilatowicz@Sun.COM #include <sys/list.h> 35*7675SEdward.Pilatowicz@Sun.COM #include <sys/types.h> 36*7675SEdward.Pilatowicz@Sun.COM #include <sys/mkdev.h> 37*7675SEdward.Pilatowicz@Sun.COM #include <sys/mman.h> 38*7675SEdward.Pilatowicz@Sun.COM #include <sys/mnttab.h> 39*7675SEdward.Pilatowicz@Sun.COM 40*7675SEdward.Pilatowicz@Sun.COM #include "Pcontrol.h" 41*7675SEdward.Pilatowicz@Sun.COM 42*7675SEdward.Pilatowicz@Sun.COM struct path_node { 43*7675SEdward.Pilatowicz@Sun.COM struct path_node *pn_next; 44*7675SEdward.Pilatowicz@Sun.COM char *pn_path; 45*7675SEdward.Pilatowicz@Sun.COM }; 46*7675SEdward.Pilatowicz@Sun.COM typedef struct path_node path_node_t; 47*7675SEdward.Pilatowicz@Sun.COM 48*7675SEdward.Pilatowicz@Sun.COM static path_node_t * 49*7675SEdward.Pilatowicz@Sun.COM pn_push(path_node_t **pnp, char *path) 50*7675SEdward.Pilatowicz@Sun.COM { 51*7675SEdward.Pilatowicz@Sun.COM path_node_t *pn; 52*7675SEdward.Pilatowicz@Sun.COM 53*7675SEdward.Pilatowicz@Sun.COM if ((pn = calloc(sizeof (path_node_t), 1)) == NULL) 54*7675SEdward.Pilatowicz@Sun.COM return (NULL); 55*7675SEdward.Pilatowicz@Sun.COM 56*7675SEdward.Pilatowicz@Sun.COM if ((pn->pn_path = strdup(path)) == NULL) { 57*7675SEdward.Pilatowicz@Sun.COM free(pn); 58*7675SEdward.Pilatowicz@Sun.COM return (NULL); 59*7675SEdward.Pilatowicz@Sun.COM } 60*7675SEdward.Pilatowicz@Sun.COM pn->pn_next = *pnp; 61*7675SEdward.Pilatowicz@Sun.COM return (*pnp = pn); 62*7675SEdward.Pilatowicz@Sun.COM } 63*7675SEdward.Pilatowicz@Sun.COM 64*7675SEdward.Pilatowicz@Sun.COM static void 65*7675SEdward.Pilatowicz@Sun.COM pn_free(path_node_t **pnp) 66*7675SEdward.Pilatowicz@Sun.COM { 67*7675SEdward.Pilatowicz@Sun.COM path_node_t *pn; 68*7675SEdward.Pilatowicz@Sun.COM 69*7675SEdward.Pilatowicz@Sun.COM while (*pnp != NULL) { 70*7675SEdward.Pilatowicz@Sun.COM pn = *pnp; 71*7675SEdward.Pilatowicz@Sun.COM *pnp = pn->pn_next; 72*7675SEdward.Pilatowicz@Sun.COM free(pn->pn_path); 73*7675SEdward.Pilatowicz@Sun.COM free(pn); 74*7675SEdward.Pilatowicz@Sun.COM } 75*7675SEdward.Pilatowicz@Sun.COM } 76*7675SEdward.Pilatowicz@Sun.COM 77*7675SEdward.Pilatowicz@Sun.COM static void 78*7675SEdward.Pilatowicz@Sun.COM pn_free2(path_node_t **pn1, path_node_t **pn2) 79*7675SEdward.Pilatowicz@Sun.COM { 80*7675SEdward.Pilatowicz@Sun.COM pn_free(pn1); 81*7675SEdward.Pilatowicz@Sun.COM pn_free(pn2); 82*7675SEdward.Pilatowicz@Sun.COM } 83*7675SEdward.Pilatowicz@Sun.COM 84*7675SEdward.Pilatowicz@Sun.COM static char * 85*7675SEdward.Pilatowicz@Sun.COM pn_pop(path_node_t **pnp, char *path) 86*7675SEdward.Pilatowicz@Sun.COM { 87*7675SEdward.Pilatowicz@Sun.COM path_node_t *pn; 88*7675SEdward.Pilatowicz@Sun.COM 89*7675SEdward.Pilatowicz@Sun.COM if (*pnp == NULL) 90*7675SEdward.Pilatowicz@Sun.COM return (NULL); 91*7675SEdward.Pilatowicz@Sun.COM 92*7675SEdward.Pilatowicz@Sun.COM pn = *pnp; 93*7675SEdward.Pilatowicz@Sun.COM *pnp = pn->pn_next; 94*7675SEdward.Pilatowicz@Sun.COM pn->pn_next = NULL; 95*7675SEdward.Pilatowicz@Sun.COM 96*7675SEdward.Pilatowicz@Sun.COM if (path == NULL) { 97*7675SEdward.Pilatowicz@Sun.COM pn_free(&pn); 98*7675SEdward.Pilatowicz@Sun.COM return (NULL); 99*7675SEdward.Pilatowicz@Sun.COM } 100*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(path, pn->pn_path, PATH_MAX); 101*7675SEdward.Pilatowicz@Sun.COM pn_free(&pn); 102*7675SEdward.Pilatowicz@Sun.COM return (path); 103*7675SEdward.Pilatowicz@Sun.COM } 104*7675SEdward.Pilatowicz@Sun.COM 105*7675SEdward.Pilatowicz@Sun.COM 106*7675SEdward.Pilatowicz@Sun.COM /* 107*7675SEdward.Pilatowicz@Sun.COM * Libzonecfg.so links against libproc, so libproc can't link against 108*7675SEdward.Pilatowicz@Sun.COM * libzonecfg.so. Also, libzonecfg.so is optional and might not be 109*7675SEdward.Pilatowicz@Sun.COM * installed. Hence instead of relying on linking to access libzonecfg.so, 110*7675SEdward.Pilatowicz@Sun.COM * we'll try dlopening it here. This trick is borrowed from 111*7675SEdward.Pilatowicz@Sun.COM * libc`zone_get_id(), see that function for more detailed comments. 112*7675SEdward.Pilatowicz@Sun.COM */ 113*7675SEdward.Pilatowicz@Sun.COM static int 114*7675SEdward.Pilatowicz@Sun.COM i_zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 115*7675SEdward.Pilatowicz@Sun.COM { 116*7675SEdward.Pilatowicz@Sun.COM typedef int (*zone_get_zonepath_t)(char *, char *, size_t); 117*7675SEdward.Pilatowicz@Sun.COM static zone_get_zonepath_t zone_get_zonepath_fp = NULL; 118*7675SEdward.Pilatowicz@Sun.COM 119*7675SEdward.Pilatowicz@Sun.COM if (zone_get_zonepath_fp == NULL) { 120*7675SEdward.Pilatowicz@Sun.COM /* There's no harm in doing this multiple times. */ 121*7675SEdward.Pilatowicz@Sun.COM void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY); 122*7675SEdward.Pilatowicz@Sun.COM void *sym = (void *)(-1); 123*7675SEdward.Pilatowicz@Sun.COM if (dlhandle != NULL && 124*7675SEdward.Pilatowicz@Sun.COM (sym = dlsym(dlhandle, "zone_get_zonepath")) == NULL) { 125*7675SEdward.Pilatowicz@Sun.COM sym = (void *)(-1); 126*7675SEdward.Pilatowicz@Sun.COM (void) dlclose(dlhandle); 127*7675SEdward.Pilatowicz@Sun.COM } 128*7675SEdward.Pilatowicz@Sun.COM zone_get_zonepath_fp = (zone_get_zonepath_t)sym; 129*7675SEdward.Pilatowicz@Sun.COM } 130*7675SEdward.Pilatowicz@Sun.COM 131*7675SEdward.Pilatowicz@Sun.COM /* If we've successfully loaded it, call the real function */ 132*7675SEdward.Pilatowicz@Sun.COM if (zone_get_zonepath_fp != (zone_get_zonepath_t)(-1)) 133*7675SEdward.Pilatowicz@Sun.COM return (zone_get_zonepath_fp(zone_name, zonepath, rp_sz)); 134*7675SEdward.Pilatowicz@Sun.COM return (Z_NO_ZONE); 135*7675SEdward.Pilatowicz@Sun.COM } 136*7675SEdward.Pilatowicz@Sun.COM 137*7675SEdward.Pilatowicz@Sun.COM char * 138*7675SEdward.Pilatowicz@Sun.COM Pbrandname(struct ps_prochandle *P, char *buf, size_t buflen) 139*7675SEdward.Pilatowicz@Sun.COM { 140*7675SEdward.Pilatowicz@Sun.COM long addr; 141*7675SEdward.Pilatowicz@Sun.COM 142*7675SEdward.Pilatowicz@Sun.COM if ((addr = Pgetauxval(P, AT_SUN_BRANDNAME)) == -1) 143*7675SEdward.Pilatowicz@Sun.COM return (NULL); 144*7675SEdward.Pilatowicz@Sun.COM 145*7675SEdward.Pilatowicz@Sun.COM if (Pread_string(P, buf, buflen, addr) == -1) 146*7675SEdward.Pilatowicz@Sun.COM return (NULL); 147*7675SEdward.Pilatowicz@Sun.COM 148*7675SEdward.Pilatowicz@Sun.COM return (buf); 149*7675SEdward.Pilatowicz@Sun.COM } 150*7675SEdward.Pilatowicz@Sun.COM 151*7675SEdward.Pilatowicz@Sun.COM /* 152*7675SEdward.Pilatowicz@Sun.COM * Get the zone name from the core file if we have it; look up the 153*7675SEdward.Pilatowicz@Sun.COM * name based on the zone id if this is a live process. 154*7675SEdward.Pilatowicz@Sun.COM */ 155*7675SEdward.Pilatowicz@Sun.COM char * 156*7675SEdward.Pilatowicz@Sun.COM Pzonename(struct ps_prochandle *P, char *s, size_t n) 157*7675SEdward.Pilatowicz@Sun.COM { 158*7675SEdward.Pilatowicz@Sun.COM if (P->state == PS_IDLE) { 159*7675SEdward.Pilatowicz@Sun.COM errno = ENODATA; 160*7675SEdward.Pilatowicz@Sun.COM return (NULL); 161*7675SEdward.Pilatowicz@Sun.COM } 162*7675SEdward.Pilatowicz@Sun.COM 163*7675SEdward.Pilatowicz@Sun.COM if (P->state == PS_DEAD) { 164*7675SEdward.Pilatowicz@Sun.COM if (P->core->core_zonename == NULL) { 165*7675SEdward.Pilatowicz@Sun.COM errno = ENODATA; 166*7675SEdward.Pilatowicz@Sun.COM return (NULL); 167*7675SEdward.Pilatowicz@Sun.COM } 168*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->core->core_zonename, n); 169*7675SEdward.Pilatowicz@Sun.COM } else { 170*7675SEdward.Pilatowicz@Sun.COM if (getzonenamebyid(P->status.pr_zoneid, s, n) < 0) 171*7675SEdward.Pilatowicz@Sun.COM return (NULL); 172*7675SEdward.Pilatowicz@Sun.COM s[n - 1] = '\0'; 173*7675SEdward.Pilatowicz@Sun.COM } 174*7675SEdward.Pilatowicz@Sun.COM return (s); 175*7675SEdward.Pilatowicz@Sun.COM } 176*7675SEdward.Pilatowicz@Sun.COM 177*7675SEdward.Pilatowicz@Sun.COM char * 178*7675SEdward.Pilatowicz@Sun.COM Pzoneroot(struct ps_prochandle *P, char *s, size_t n) 179*7675SEdward.Pilatowicz@Sun.COM { 180*7675SEdward.Pilatowicz@Sun.COM char zname[ZONENAME_MAX], zpath[PATH_MAX], tmp[PATH_MAX]; 181*7675SEdward.Pilatowicz@Sun.COM int rv; 182*7675SEdward.Pilatowicz@Sun.COM 183*7675SEdward.Pilatowicz@Sun.COM if (P->zoneroot != NULL) { 184*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->zoneroot, n); 185*7675SEdward.Pilatowicz@Sun.COM return (s); 186*7675SEdward.Pilatowicz@Sun.COM } 187*7675SEdward.Pilatowicz@Sun.COM 188*7675SEdward.Pilatowicz@Sun.COM if ((Pzonename(P, zname, sizeof (zname)) == NULL) || 189*7675SEdward.Pilatowicz@Sun.COM (strcmp(zname, GLOBAL_ZONENAME) == 0)) { 190*7675SEdward.Pilatowicz@Sun.COM if ((P->zoneroot = strdup("")) == NULL) { 191*7675SEdward.Pilatowicz@Sun.COM errno = ENOMEM; 192*7675SEdward.Pilatowicz@Sun.COM return (NULL); 193*7675SEdward.Pilatowicz@Sun.COM } 194*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzoneroot defaulting to '%s'\n", GLOBAL_ZONENAME); 195*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->zoneroot, n); 196*7675SEdward.Pilatowicz@Sun.COM return (s); 197*7675SEdward.Pilatowicz@Sun.COM } 198*7675SEdward.Pilatowicz@Sun.COM 199*7675SEdward.Pilatowicz@Sun.COM if (i_zone_get_zonepath(zname, zpath, sizeof (zpath)) != Z_OK) { 200*7675SEdward.Pilatowicz@Sun.COM if ((P->zoneroot = strdup("")) == NULL) { 201*7675SEdward.Pilatowicz@Sun.COM errno = ENOMEM; 202*7675SEdward.Pilatowicz@Sun.COM return (NULL); 203*7675SEdward.Pilatowicz@Sun.COM } 204*7675SEdward.Pilatowicz@Sun.COM dprintf( 205*7675SEdward.Pilatowicz@Sun.COM "Pzoneroot zone not found '%s', defaulting to '%s'\n", 206*7675SEdward.Pilatowicz@Sun.COM zname, GLOBAL_ZONENAME); 207*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->zoneroot, n); 208*7675SEdward.Pilatowicz@Sun.COM return (s); 209*7675SEdward.Pilatowicz@Sun.COM } 210*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(zpath, "/root", sizeof (zpath)); 211*7675SEdward.Pilatowicz@Sun.COM 212*7675SEdward.Pilatowicz@Sun.COM if ((rv = resolvepath(zpath, tmp, sizeof (tmp) - 1)) < 0) { 213*7675SEdward.Pilatowicz@Sun.COM if ((P->zoneroot = strdup("")) == NULL) { 214*7675SEdward.Pilatowicz@Sun.COM errno = ENOMEM; 215*7675SEdward.Pilatowicz@Sun.COM return (NULL); 216*7675SEdward.Pilatowicz@Sun.COM } 217*7675SEdward.Pilatowicz@Sun.COM dprintf( 218*7675SEdward.Pilatowicz@Sun.COM "Pzoneroot can't access '%s:%s', defaulting to '%s'\n", 219*7675SEdward.Pilatowicz@Sun.COM zname, zpath, GLOBAL_ZONENAME); 220*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->zoneroot, n); 221*7675SEdward.Pilatowicz@Sun.COM return (s); 222*7675SEdward.Pilatowicz@Sun.COM } 223*7675SEdward.Pilatowicz@Sun.COM tmp[rv] = '\0'; 224*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(zpath, tmp, sizeof (zpath)); 225*7675SEdward.Pilatowicz@Sun.COM 226*7675SEdward.Pilatowicz@Sun.COM if ((P->zoneroot = strdup(zpath)) == NULL) { 227*7675SEdward.Pilatowicz@Sun.COM errno = ENOMEM; 228*7675SEdward.Pilatowicz@Sun.COM return (NULL); 229*7675SEdward.Pilatowicz@Sun.COM } 230*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzoneroot found zone root '%s:%s'\n", zname, zpath); 231*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, P->zoneroot, n); 232*7675SEdward.Pilatowicz@Sun.COM return (s); 233*7675SEdward.Pilatowicz@Sun.COM } 234*7675SEdward.Pilatowicz@Sun.COM 235*7675SEdward.Pilatowicz@Sun.COM /* 236*7675SEdward.Pilatowicz@Sun.COM * Plofspath() takes a path, "path", and removes any lofs components from 237*7675SEdward.Pilatowicz@Sun.COM * that path. The resultant path (if different from the starting path) 238*7675SEdward.Pilatowicz@Sun.COM * is placed in "s", which is limited to "n" characters, and the return 239*7675SEdward.Pilatowicz@Sun.COM * value is the pointer s. If there are no lofs components in the path 240*7675SEdward.Pilatowicz@Sun.COM * the NULL is returned and s is not modified. It's ok for "path" and 241*7675SEdward.Pilatowicz@Sun.COM * "s" to be the same pointer. (ie, the results can be stored directly 242*7675SEdward.Pilatowicz@Sun.COM * in the input buffer.) The path that is passed in must be an absolute 243*7675SEdward.Pilatowicz@Sun.COM * path. 244*7675SEdward.Pilatowicz@Sun.COM * 245*7675SEdward.Pilatowicz@Sun.COM * Example: 246*7675SEdward.Pilatowicz@Sun.COM * if "path" == "/foo/bar", and "/candy/" is lofs mounted on "/foo/" 247*7675SEdward.Pilatowicz@Sun.COM * then "/candy/bar/" will be written into "s" and "s" will be returned. 248*7675SEdward.Pilatowicz@Sun.COM */ 249*7675SEdward.Pilatowicz@Sun.COM char * 250*7675SEdward.Pilatowicz@Sun.COM Plofspath(const char *path, char *s, size_t n) 251*7675SEdward.Pilatowicz@Sun.COM { 252*7675SEdward.Pilatowicz@Sun.COM char tmp[PATH_MAX + 1]; 253*7675SEdward.Pilatowicz@Sun.COM struct mnttab mt, mt_find; 254*7675SEdward.Pilatowicz@Sun.COM FILE *fp; 255*7675SEdward.Pilatowicz@Sun.COM char *p, *p2; 256*7675SEdward.Pilatowicz@Sun.COM int rv; 257*7675SEdward.Pilatowicz@Sun.COM 258*7675SEdward.Pilatowicz@Sun.COM dprintf("Plofspath path '%s'\n", path); 259*7675SEdward.Pilatowicz@Sun.COM 260*7675SEdward.Pilatowicz@Sun.COM /* We only deal with absolute paths */ 261*7675SEdward.Pilatowicz@Sun.COM if (path[0] != '/') 262*7675SEdward.Pilatowicz@Sun.COM return (NULL); 263*7675SEdward.Pilatowicz@Sun.COM 264*7675SEdward.Pilatowicz@Sun.COM /* Open /etc/mnttab */ 265*7675SEdward.Pilatowicz@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) 266*7675SEdward.Pilatowicz@Sun.COM return (NULL); 267*7675SEdward.Pilatowicz@Sun.COM 268*7675SEdward.Pilatowicz@Sun.COM /* Make a copy of the path so that we can muck with it */ 269*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp, path, sizeof (tmp) - 1); 270*7675SEdward.Pilatowicz@Sun.COM 271*7675SEdward.Pilatowicz@Sun.COM /* 272*7675SEdward.Pilatowicz@Sun.COM * Use resolvepath() to make sure there are no consecutive or 273*7675SEdward.Pilatowicz@Sun.COM * trailing '/'s in the path. 274*7675SEdward.Pilatowicz@Sun.COM */ 275*7675SEdward.Pilatowicz@Sun.COM if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 276*7675SEdward.Pilatowicz@Sun.COM tmp[rv] = '\0'; 277*7675SEdward.Pilatowicz@Sun.COM 278*7675SEdward.Pilatowicz@Sun.COM /* 279*7675SEdward.Pilatowicz@Sun.COM * So now we're going to search the path for any components that 280*7675SEdward.Pilatowicz@Sun.COM * might be lofs mounts. We'll start out search from the full 281*7675SEdward.Pilatowicz@Sun.COM * path and then step back through each parent directly till 282*7675SEdward.Pilatowicz@Sun.COM * we reach the root. If we find a lofs mount point in the path 283*7675SEdward.Pilatowicz@Sun.COM * then we'll replace the initial portion of the path (up 284*7675SEdward.Pilatowicz@Sun.COM * to that mount point) with the source of that mount point 285*7675SEdward.Pilatowicz@Sun.COM * and then start our search over again. 286*7675SEdward.Pilatowicz@Sun.COM * 287*7675SEdward.Pilatowicz@Sun.COM * Here's some of the variables we're going to use: 288*7675SEdward.Pilatowicz@Sun.COM * 289*7675SEdward.Pilatowicz@Sun.COM * tmp - A pointer to our working copy of the path. Sometimes 290*7675SEdward.Pilatowicz@Sun.COM * this path will be divided into two strings by a 291*7675SEdward.Pilatowicz@Sun.COM * '\0' (NUL) character. The first string is the 292*7675SEdward.Pilatowicz@Sun.COM * component we're currently checking and the second 293*7675SEdward.Pilatowicz@Sun.COM * string is the path components we've already checked. 294*7675SEdward.Pilatowicz@Sun.COM * 295*7675SEdward.Pilatowicz@Sun.COM * p - A pointer to the last '/' seen in the string. 296*7675SEdward.Pilatowicz@Sun.COM * 297*7675SEdward.Pilatowicz@Sun.COM * p[1] - A pointer to the component of the string we've already 298*7675SEdward.Pilatowicz@Sun.COM * checked. 299*7675SEdward.Pilatowicz@Sun.COM * 300*7675SEdward.Pilatowicz@Sun.COM * Initially, p will point to the end of our path and p[1] will point 301*7675SEdward.Pilatowicz@Sun.COM * to an extra '\0' (NUL) that we'll append to the end of the string. 302*7675SEdward.Pilatowicz@Sun.COM * (This is why we declared tmp with a size of PATH_MAX + 1). 303*7675SEdward.Pilatowicz@Sun.COM */ 304*7675SEdward.Pilatowicz@Sun.COM p = &tmp[strlen(tmp)]; 305*7675SEdward.Pilatowicz@Sun.COM p[1] = '\0'; 306*7675SEdward.Pilatowicz@Sun.COM for (;;) { 307*7675SEdward.Pilatowicz@Sun.COM /* Check if tmp is a mount point */ 308*7675SEdward.Pilatowicz@Sun.COM rewind(fp); 309*7675SEdward.Pilatowicz@Sun.COM bzero(&mt_find, sizeof (mt_find)); 310*7675SEdward.Pilatowicz@Sun.COM mt_find.mnt_mountp = tmp; 311*7675SEdward.Pilatowicz@Sun.COM rv = getmntany(fp, &mt, &mt_find); 312*7675SEdward.Pilatowicz@Sun.COM 313*7675SEdward.Pilatowicz@Sun.COM /* We only care about lofs mount points */ 314*7675SEdward.Pilatowicz@Sun.COM if ((rv == 0) && (strcmp(mt.mnt_fstype, "lofs") == 0)) { 315*7675SEdward.Pilatowicz@Sun.COM char tmp2[PATH_MAX + 1]; 316*7675SEdward.Pilatowicz@Sun.COM 317*7675SEdward.Pilatowicz@Sun.COM /* 318*7675SEdward.Pilatowicz@Sun.COM * We found a lofs mount. Update the path that we're 319*7675SEdward.Pilatowicz@Sun.COM * checking and start over. This means append the 320*7675SEdward.Pilatowicz@Sun.COM * portion of the path we've already checked to the 321*7675SEdward.Pilatowicz@Sun.COM * source of the lofs mount and re-start this entire 322*7675SEdward.Pilatowicz@Sun.COM * lofs resolution loop. Use resolvepath() to make 323*7675SEdward.Pilatowicz@Sun.COM * sure there are no consecutive or trailing '/'s 324*7675SEdward.Pilatowicz@Sun.COM * in the path. 325*7675SEdward.Pilatowicz@Sun.COM */ 326*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp2, mt.mnt_special, sizeof (tmp2) - 1); 327*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp2, "/", sizeof (tmp2) - 1); 328*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp2, &p[1], sizeof (tmp2) - 1); 329*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp, tmp2, sizeof (tmp) - 1); 330*7675SEdward.Pilatowicz@Sun.COM if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 331*7675SEdward.Pilatowicz@Sun.COM tmp[rv] = '\0'; 332*7675SEdward.Pilatowicz@Sun.COM p = &tmp[strlen(tmp)]; 333*7675SEdward.Pilatowicz@Sun.COM p[1] = '\0'; 334*7675SEdward.Pilatowicz@Sun.COM continue; 335*7675SEdward.Pilatowicz@Sun.COM } 336*7675SEdward.Pilatowicz@Sun.COM 337*7675SEdward.Pilatowicz@Sun.COM /* No lofs mount found */ 338*7675SEdward.Pilatowicz@Sun.COM if ((p2 = strrchr(tmp, '/')) == NULL) { 339*7675SEdward.Pilatowicz@Sun.COM char tmp2[PATH_MAX]; 340*7675SEdward.Pilatowicz@Sun.COM 341*7675SEdward.Pilatowicz@Sun.COM /* 342*7675SEdward.Pilatowicz@Sun.COM * We know that tmp was an absolute path, so if we 343*7675SEdward.Pilatowicz@Sun.COM * made it here we know that (p == tmp) and that 344*7675SEdward.Pilatowicz@Sun.COM * (*p == '\0'). This means that we've managed 345*7675SEdward.Pilatowicz@Sun.COM * to check the whole path and so we're done. 346*7675SEdward.Pilatowicz@Sun.COM */ 347*7675SEdward.Pilatowicz@Sun.COM assert(p == tmp); 348*7675SEdward.Pilatowicz@Sun.COM assert(p[0] == '\0'); 349*7675SEdward.Pilatowicz@Sun.COM (void) fclose(fp); 350*7675SEdward.Pilatowicz@Sun.COM 351*7675SEdward.Pilatowicz@Sun.COM /* Restore the leading '/' in the path */ 352*7675SEdward.Pilatowicz@Sun.COM p[0] = '/'; 353*7675SEdward.Pilatowicz@Sun.COM 354*7675SEdward.Pilatowicz@Sun.COM if (strcmp(tmp, path) == 0) { 355*7675SEdward.Pilatowicz@Sun.COM /* The path didn't change */ 356*7675SEdward.Pilatowicz@Sun.COM return (NULL); 357*7675SEdward.Pilatowicz@Sun.COM } 358*7675SEdward.Pilatowicz@Sun.COM 359*7675SEdward.Pilatowicz@Sun.COM /* 360*7675SEdward.Pilatowicz@Sun.COM * It's possible that lofs source path we just 361*7675SEdward.Pilatowicz@Sun.COM * obtained contains a symbolic link. Use 362*7675SEdward.Pilatowicz@Sun.COM * resolvepath() to clean it up. 363*7675SEdward.Pilatowicz@Sun.COM */ 364*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp2, tmp, sizeof (tmp2)); 365*7675SEdward.Pilatowicz@Sun.COM if ((rv = resolvepath(tmp, tmp, sizeof (tmp) - 1)) >= 0) 366*7675SEdward.Pilatowicz@Sun.COM tmp[rv] = '\0'; 367*7675SEdward.Pilatowicz@Sun.COM 368*7675SEdward.Pilatowicz@Sun.COM /* 369*7675SEdward.Pilatowicz@Sun.COM * It's always possible that our lofs source path is 370*7675SEdward.Pilatowicz@Sun.COM * actually another lofs mount. So call ourselves 371*7675SEdward.Pilatowicz@Sun.COM * recursively to resolve that path. 372*7675SEdward.Pilatowicz@Sun.COM */ 373*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(tmp, tmp, PATH_MAX); 374*7675SEdward.Pilatowicz@Sun.COM 375*7675SEdward.Pilatowicz@Sun.COM /* Copy out our final resolved lofs source path */ 376*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, tmp, n); 377*7675SEdward.Pilatowicz@Sun.COM dprintf("Plofspath path result '%s'\n", s); 378*7675SEdward.Pilatowicz@Sun.COM return (s); 379*7675SEdward.Pilatowicz@Sun.COM } 380*7675SEdward.Pilatowicz@Sun.COM 381*7675SEdward.Pilatowicz@Sun.COM /* 382*7675SEdward.Pilatowicz@Sun.COM * So the path we just checked is not a lofs mount. Next we 383*7675SEdward.Pilatowicz@Sun.COM * want to check the parent path component for a lofs mount. 384*7675SEdward.Pilatowicz@Sun.COM * 385*7675SEdward.Pilatowicz@Sun.COM * First, restore any '/' that we replaced with a '\0' (NUL). 386*7675SEdward.Pilatowicz@Sun.COM * We can determine if we should do this by looking at p[1]. 387*7675SEdward.Pilatowicz@Sun.COM * If p[1] points to a '\0' (NUL) then we know that p points 388*7675SEdward.Pilatowicz@Sun.COM * to the end of the string and there is no '/' to restore. 389*7675SEdward.Pilatowicz@Sun.COM * if p[1] doesn't point to a '\0' (NUL) then it points to 390*7675SEdward.Pilatowicz@Sun.COM * the part of the path that we've already verified so there 391*7675SEdward.Pilatowicz@Sun.COM * is a '/' to restore. 392*7675SEdward.Pilatowicz@Sun.COM */ 393*7675SEdward.Pilatowicz@Sun.COM if (p[1] != '\0') 394*7675SEdward.Pilatowicz@Sun.COM p[0] = '/'; 395*7675SEdward.Pilatowicz@Sun.COM 396*7675SEdward.Pilatowicz@Sun.COM /* 397*7675SEdward.Pilatowicz@Sun.COM * Second, replace the last '/' in the part of the path 398*7675SEdward.Pilatowicz@Sun.COM * that we've already checked with a '\0' (NUL) so that 399*7675SEdward.Pilatowicz@Sun.COM * when we loop around we check the parent component of the 400*7675SEdward.Pilatowicz@Sun.COM * path. 401*7675SEdward.Pilatowicz@Sun.COM */ 402*7675SEdward.Pilatowicz@Sun.COM p2[0] = '\0'; 403*7675SEdward.Pilatowicz@Sun.COM p = p2; 404*7675SEdward.Pilatowicz@Sun.COM } 405*7675SEdward.Pilatowicz@Sun.COM /*NOTREACHED*/ 406*7675SEdward.Pilatowicz@Sun.COM } 407*7675SEdward.Pilatowicz@Sun.COM 408*7675SEdward.Pilatowicz@Sun.COM /* 409*7675SEdward.Pilatowicz@Sun.COM * Pzonepath() - Way too much code to attempt to derive the full path of 410*7675SEdward.Pilatowicz@Sun.COM * an object within a zone. 411*7675SEdward.Pilatowicz@Sun.COM * 412*7675SEdward.Pilatowicz@Sun.COM * Pzonepath() takes a path and attempts to resolve it relative to the 413*7675SEdward.Pilatowicz@Sun.COM * root associated with the current process handle. If it fails it will 414*7675SEdward.Pilatowicz@Sun.COM * not update the results string. It is safe to specify the same pointer 415*7675SEdward.Pilatowicz@Sun.COM * for the file string and the results string. 416*7675SEdward.Pilatowicz@Sun.COM * 417*7675SEdward.Pilatowicz@Sun.COM * Doing this resolution is more difficult than it initially sounds. 418*7675SEdward.Pilatowicz@Sun.COM * We can't simply append the file path to the zone root, because in 419*7675SEdward.Pilatowicz@Sun.COM * a root directory, '..' is treated the same as '.'. Also, symbolic 420*7675SEdward.Pilatowicz@Sun.COM * links that specify an absolute path need to be interpreted relative 421*7675SEdward.Pilatowicz@Sun.COM * to the zone root. 422*7675SEdward.Pilatowicz@Sun.COM * 423*7675SEdward.Pilatowicz@Sun.COM * It seems like perhaps we could do a chroot(<zone root>) followed by a 424*7675SEdward.Pilatowicz@Sun.COM * resolvepath(). But we can't do this because chroot requires special 425*7675SEdward.Pilatowicz@Sun.COM * privileges and affects the entire process. Perhaps if there was a 426*7675SEdward.Pilatowicz@Sun.COM * special version of resolvepath() which took an addition root path 427*7675SEdward.Pilatowicz@Sun.COM * we could use that, but this isn't ideal either. The reason is 428*7675SEdward.Pilatowicz@Sun.COM * that we want to have special handling for native paths. (A native path 429*7675SEdward.Pilatowicz@Sun.COM * is a path that begins with "/native/" or "/.SUNWnative/".) Native 430*7675SEdward.Pilatowicz@Sun.COM * paths could be passed explicity to this function or could be embedded 431*7675SEdward.Pilatowicz@Sun.COM * in a symlink that is part of the path passed into this function. 432*7675SEdward.Pilatowicz@Sun.COM * These paths are always lofs mounts of global zone paths, but lofs 433*7675SEdward.Pilatowicz@Sun.COM * mounts only exist when a zone is booted. So if we were to try to do 434*7675SEdward.Pilatowicz@Sun.COM * a resolvepath() on a native path when the zone wasn't booted the 435*7675SEdward.Pilatowicz@Sun.COM * resolvepath() would fail even though we know that the components 436*7675SEdward.Pilatowicz@Sun.COM * exists in the global zone. 437*7675SEdward.Pilatowicz@Sun.COM * 438*7675SEdward.Pilatowicz@Sun.COM * Given all these constraints, we just implement a path walking function 439*7675SEdward.Pilatowicz@Sun.COM * that resolves a file path relative to a zone root by manually inspecting 440*7675SEdward.Pilatowicz@Sun.COM * each of the path components and verifying its existence. This means that 441*7675SEdward.Pilatowicz@Sun.COM * we must have access to the zone and that all the components of the 442*7675SEdward.Pilatowicz@Sun.COM * path must exist for this operation to succeed. 443*7675SEdward.Pilatowicz@Sun.COM */ 444*7675SEdward.Pilatowicz@Sun.COM char * 445*7675SEdward.Pilatowicz@Sun.COM Pzonepath(struct ps_prochandle *P, const char *path, char *s, size_t n) 446*7675SEdward.Pilatowicz@Sun.COM { 447*7675SEdward.Pilatowicz@Sun.COM char zroot[PATH_MAX], zpath[PATH_MAX], tmp[PATH_MAX], link[PATH_MAX]; 448*7675SEdward.Pilatowicz@Sun.COM path_node_t *pn_stack = NULL, *pn_links = NULL, *pn; 449*7675SEdward.Pilatowicz@Sun.COM struct stat64 sb; 450*7675SEdward.Pilatowicz@Sun.COM char *p; 451*7675SEdward.Pilatowicz@Sun.COM int i, rv; 452*7675SEdward.Pilatowicz@Sun.COM 453*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath lookup '%s'\n", path); 454*7675SEdward.Pilatowicz@Sun.COM 455*7675SEdward.Pilatowicz@Sun.COM /* First lookup the zone root */ 456*7675SEdward.Pilatowicz@Sun.COM if (Pzoneroot(P, zroot, sizeof (zroot)) == NULL) 457*7675SEdward.Pilatowicz@Sun.COM return (NULL); 458*7675SEdward.Pilatowicz@Sun.COM 459*7675SEdward.Pilatowicz@Sun.COM /* 460*7675SEdward.Pilatowicz@Sun.COM * Make a temporary copy of the path specified. 461*7675SEdward.Pilatowicz@Sun.COM * If it's a relative path then make it into an absolute path. 462*7675SEdward.Pilatowicz@Sun.COM */ 463*7675SEdward.Pilatowicz@Sun.COM tmp[0] = '\0'; 464*7675SEdward.Pilatowicz@Sun.COM if (path[0] != '/') 465*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp, "/", sizeof (tmp)); 466*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp, path, sizeof (tmp)); 467*7675SEdward.Pilatowicz@Sun.COM 468*7675SEdward.Pilatowicz@Sun.COM /* 469*7675SEdward.Pilatowicz@Sun.COM * If the path that was passed in is the zone root, we're done. 470*7675SEdward.Pilatowicz@Sun.COM * If the path that was passed in already contains the zone root 471*7675SEdward.Pilatowicz@Sun.COM * then strip the zone root out and verify the rest of the path. 472*7675SEdward.Pilatowicz@Sun.COM */ 473*7675SEdward.Pilatowicz@Sun.COM if (strcmp(tmp, zroot) == 0) { 474*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(zroot, zroot, sizeof (zroot)); 475*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath found zone path (1) '%s'\n", zroot); 476*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, zroot, n); 477*7675SEdward.Pilatowicz@Sun.COM return (s); 478*7675SEdward.Pilatowicz@Sun.COM } 479*7675SEdward.Pilatowicz@Sun.COM i = strlen(zroot); 480*7675SEdward.Pilatowicz@Sun.COM if ((strncmp(tmp, zroot, i) == 0) && (tmp[i] == '/')) 481*7675SEdward.Pilatowicz@Sun.COM (void) memmove(tmp, tmp + i, strlen(tmp + i) + 1); 482*7675SEdward.Pilatowicz@Sun.COM 483*7675SEdward.Pilatowicz@Sun.COM /* If no path is passed in, then it maps to the zone root */ 484*7675SEdward.Pilatowicz@Sun.COM if (strlen(tmp) == 0) { 485*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(zroot, zroot, sizeof (zroot)); 486*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath found zone path (2) '%s'\n", zroot); 487*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, zroot, n); 488*7675SEdward.Pilatowicz@Sun.COM return (s); 489*7675SEdward.Pilatowicz@Sun.COM } 490*7675SEdward.Pilatowicz@Sun.COM 491*7675SEdward.Pilatowicz@Sun.COM /* 492*7675SEdward.Pilatowicz@Sun.COM * Push each path component that we plan to verify onto a stack of 493*7675SEdward.Pilatowicz@Sun.COM * path components, with parent components at the top of the stack. 494*7675SEdward.Pilatowicz@Sun.COM * So for example, if we're going to verify the path /foo/bar/bang 495*7675SEdward.Pilatowicz@Sun.COM * then our stack will look like: 496*7675SEdward.Pilatowicz@Sun.COM * foo (top) 497*7675SEdward.Pilatowicz@Sun.COM * bar 498*7675SEdward.Pilatowicz@Sun.COM * bang (bottom) 499*7675SEdward.Pilatowicz@Sun.COM */ 500*7675SEdward.Pilatowicz@Sun.COM while ((p = strrchr(tmp, '/')) != NULL) { 501*7675SEdward.Pilatowicz@Sun.COM *p = '\0'; 502*7675SEdward.Pilatowicz@Sun.COM if (pn_push(&pn_stack, &p[1]) != NULL) 503*7675SEdward.Pilatowicz@Sun.COM continue; 504*7675SEdward.Pilatowicz@Sun.COM pn_free(&pn_stack); 505*7675SEdward.Pilatowicz@Sun.COM return (NULL); 506*7675SEdward.Pilatowicz@Sun.COM } 507*7675SEdward.Pilatowicz@Sun.COM 508*7675SEdward.Pilatowicz@Sun.COM /* We're going to store the final zone relative path in zpath */ 509*7675SEdward.Pilatowicz@Sun.COM *zpath = '\0'; 510*7675SEdward.Pilatowicz@Sun.COM 511*7675SEdward.Pilatowicz@Sun.COM while (pn_pop(&pn_stack, tmp) != NULL) { 512*7675SEdward.Pilatowicz@Sun.COM /* 513*7675SEdward.Pilatowicz@Sun.COM * Drop zero length path components (which come from 514*7675SEdward.Pilatowicz@Sun.COM * consecutive '/'s) and '.' path components. 515*7675SEdward.Pilatowicz@Sun.COM */ 516*7675SEdward.Pilatowicz@Sun.COM if ((strlen(tmp) == 0) || (strcmp(tmp, ".") == 0)) 517*7675SEdward.Pilatowicz@Sun.COM continue; 518*7675SEdward.Pilatowicz@Sun.COM 519*7675SEdward.Pilatowicz@Sun.COM /* 520*7675SEdward.Pilatowicz@Sun.COM * Check the current path component for '..', if found 521*7675SEdward.Pilatowicz@Sun.COM * drop any previous path component. 522*7675SEdward.Pilatowicz@Sun.COM */ 523*7675SEdward.Pilatowicz@Sun.COM if (strcmp(tmp, "..") == 0) { 524*7675SEdward.Pilatowicz@Sun.COM if ((p = strrchr(zpath, '/')) != NULL) 525*7675SEdward.Pilatowicz@Sun.COM *p = '\0'; 526*7675SEdward.Pilatowicz@Sun.COM continue; 527*7675SEdward.Pilatowicz@Sun.COM } 528*7675SEdward.Pilatowicz@Sun.COM 529*7675SEdward.Pilatowicz@Sun.COM /* The path we want to verify now is zpath + / + tmp. */ 530*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(zpath, "/", sizeof (zpath)); 531*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(zpath, tmp, sizeof (zpath)); 532*7675SEdward.Pilatowicz@Sun.COM 533*7675SEdward.Pilatowicz@Sun.COM /* 534*7675SEdward.Pilatowicz@Sun.COM * Check if this is a native object. A native object is an 535*7675SEdward.Pilatowicz@Sun.COM * object from the global zone that is running in a branded 536*7675SEdward.Pilatowicz@Sun.COM * zone. These objects are lofs mounted into a zone. So if a 537*7675SEdward.Pilatowicz@Sun.COM * branded zone is not booted then lofs mounts won't be setup 538*7675SEdward.Pilatowicz@Sun.COM * so we won't be able to find these objects. Luckily, we know 539*7675SEdward.Pilatowicz@Sun.COM * that they exist in the global zone with the same path sans 540*7675SEdward.Pilatowicz@Sun.COM * the initial native component, so we'll just strip out the 541*7675SEdward.Pilatowicz@Sun.COM * native component here. 542*7675SEdward.Pilatowicz@Sun.COM */ 543*7675SEdward.Pilatowicz@Sun.COM if ((strncmp(zpath, "/native", sizeof ("/native")) == 0) || 544*7675SEdward.Pilatowicz@Sun.COM (strncmp(zpath, "/.SUNWnative", 545*7675SEdward.Pilatowicz@Sun.COM sizeof ("/.SUNWnative")) == 0)) { 546*7675SEdward.Pilatowicz@Sun.COM 547*7675SEdward.Pilatowicz@Sun.COM /* Free any cached symlink paths */ 548*7675SEdward.Pilatowicz@Sun.COM pn_free(&pn_links); 549*7675SEdward.Pilatowicz@Sun.COM 550*7675SEdward.Pilatowicz@Sun.COM /* Reconstruct the path from our path component stack */ 551*7675SEdward.Pilatowicz@Sun.COM *zpath = '\0'; 552*7675SEdward.Pilatowicz@Sun.COM while (pn_pop(&pn_stack, tmp) != NULL) { 553*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(zpath, "/", sizeof (zpath)); 554*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(zpath, tmp, sizeof (zpath)); 555*7675SEdward.Pilatowicz@Sun.COM } 556*7675SEdward.Pilatowicz@Sun.COM 557*7675SEdward.Pilatowicz@Sun.COM /* Verify that the path actually exists */ 558*7675SEdward.Pilatowicz@Sun.COM rv = resolvepath(zpath, tmp, sizeof (tmp) - 1); 559*7675SEdward.Pilatowicz@Sun.COM if (rv < 0) { 560*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath invalid native path '%s'\n", 561*7675SEdward.Pilatowicz@Sun.COM zpath); 562*7675SEdward.Pilatowicz@Sun.COM return (NULL); 563*7675SEdward.Pilatowicz@Sun.COM } 564*7675SEdward.Pilatowicz@Sun.COM tmp[rv] = '\0'; 565*7675SEdward.Pilatowicz@Sun.COM 566*7675SEdward.Pilatowicz@Sun.COM /* Return the path */ 567*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath found native path '%s'\n", tmp); 568*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(tmp, tmp, sizeof (tmp)); 569*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, tmp, n); 570*7675SEdward.Pilatowicz@Sun.COM return (s); 571*7675SEdward.Pilatowicz@Sun.COM } 572*7675SEdward.Pilatowicz@Sun.COM 573*7675SEdward.Pilatowicz@Sun.COM /* 574*7675SEdward.Pilatowicz@Sun.COM * Check if the path points to a symlink. We do this 575*7675SEdward.Pilatowicz@Sun.COM * explicitly since any absolute symlink needs to be 576*7675SEdward.Pilatowicz@Sun.COM * interpreted relativly to the zone root and not "/". 577*7675SEdward.Pilatowicz@Sun.COM */ 578*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp, zroot, sizeof (tmp)); 579*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp, zpath, sizeof (tmp)); 580*7675SEdward.Pilatowicz@Sun.COM if (lstat64(tmp, &sb) != 0) { 581*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 582*7675SEdward.Pilatowicz@Sun.COM return (NULL); 583*7675SEdward.Pilatowicz@Sun.COM } 584*7675SEdward.Pilatowicz@Sun.COM if (!S_ISLNK(sb.st_mode)) { 585*7675SEdward.Pilatowicz@Sun.COM /* 586*7675SEdward.Pilatowicz@Sun.COM * Since the lstat64() above succeeded we know that 587*7675SEdward.Pilatowicz@Sun.COM * zpath exists, since this is not a symlink loop 588*7675SEdward.Pilatowicz@Sun.COM * around and check the next path component. 589*7675SEdward.Pilatowicz@Sun.COM */ 590*7675SEdward.Pilatowicz@Sun.COM continue; 591*7675SEdward.Pilatowicz@Sun.COM } 592*7675SEdward.Pilatowicz@Sun.COM 593*7675SEdward.Pilatowicz@Sun.COM /* 594*7675SEdward.Pilatowicz@Sun.COM * Symlink allow for paths with loops. Make sure 595*7675SEdward.Pilatowicz@Sun.COM * we're not stuck in a loop. 596*7675SEdward.Pilatowicz@Sun.COM */ 597*7675SEdward.Pilatowicz@Sun.COM for (pn = pn_links; pn != NULL; pn = pn->pn_next) { 598*7675SEdward.Pilatowicz@Sun.COM if (strcmp(zpath, pn->pn_path) != 0) 599*7675SEdward.Pilatowicz@Sun.COM continue; 600*7675SEdward.Pilatowicz@Sun.COM 601*7675SEdward.Pilatowicz@Sun.COM /* We have a loop. Fail. */ 602*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath symlink loop '%s'\n", zpath); 603*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 604*7675SEdward.Pilatowicz@Sun.COM return (NULL); 605*7675SEdward.Pilatowicz@Sun.COM } 606*7675SEdward.Pilatowicz@Sun.COM 607*7675SEdward.Pilatowicz@Sun.COM /* Save this symlink path for future loop checks */ 608*7675SEdward.Pilatowicz@Sun.COM if (pn_push(&pn_links, zpath) == NULL) { 609*7675SEdward.Pilatowicz@Sun.COM /* Out of memory */ 610*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 611*7675SEdward.Pilatowicz@Sun.COM return (NULL); 612*7675SEdward.Pilatowicz@Sun.COM } 613*7675SEdward.Pilatowicz@Sun.COM 614*7675SEdward.Pilatowicz@Sun.COM /* Now follow the contents of the symlink */ 615*7675SEdward.Pilatowicz@Sun.COM bzero(link, sizeof (link)); 616*7675SEdward.Pilatowicz@Sun.COM if (readlink(tmp, link, sizeof (link)) == -1) { 617*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 618*7675SEdward.Pilatowicz@Sun.COM return (NULL); 619*7675SEdward.Pilatowicz@Sun.COM } 620*7675SEdward.Pilatowicz@Sun.COM 621*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath following symlink '%s' -> '%s'\n", 622*7675SEdward.Pilatowicz@Sun.COM zpath, link); 623*7675SEdward.Pilatowicz@Sun.COM 624*7675SEdward.Pilatowicz@Sun.COM /* 625*7675SEdward.Pilatowicz@Sun.COM * Push each path component of the symlink target onto our 626*7675SEdward.Pilatowicz@Sun.COM * path components stack since we need to verify each one. 627*7675SEdward.Pilatowicz@Sun.COM */ 628*7675SEdward.Pilatowicz@Sun.COM while ((p = strrchr(link, '/')) != NULL) { 629*7675SEdward.Pilatowicz@Sun.COM *p = '\0'; 630*7675SEdward.Pilatowicz@Sun.COM if (pn_push(&pn_stack, &p[1]) != NULL) 631*7675SEdward.Pilatowicz@Sun.COM continue; 632*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 633*7675SEdward.Pilatowicz@Sun.COM return (NULL); 634*7675SEdward.Pilatowicz@Sun.COM } 635*7675SEdward.Pilatowicz@Sun.COM 636*7675SEdward.Pilatowicz@Sun.COM /* absolute or relative symlink? */ 637*7675SEdward.Pilatowicz@Sun.COM if (*link == '\0') { 638*7675SEdward.Pilatowicz@Sun.COM /* Absolute symlink, nuke existing zpath. */ 639*7675SEdward.Pilatowicz@Sun.COM *zpath = '\0'; 640*7675SEdward.Pilatowicz@Sun.COM continue; 641*7675SEdward.Pilatowicz@Sun.COM } 642*7675SEdward.Pilatowicz@Sun.COM 643*7675SEdward.Pilatowicz@Sun.COM /* 644*7675SEdward.Pilatowicz@Sun.COM * Relative symlink. Push the first path component of the 645*7675SEdward.Pilatowicz@Sun.COM * symlink target onto our stack for verification and then 646*7675SEdward.Pilatowicz@Sun.COM * remove the current path component from zpath. 647*7675SEdward.Pilatowicz@Sun.COM */ 648*7675SEdward.Pilatowicz@Sun.COM if (pn_push(&pn_stack, link) == NULL) { 649*7675SEdward.Pilatowicz@Sun.COM pn_free2(&pn_stack, &pn_links); 650*7675SEdward.Pilatowicz@Sun.COM return (NULL); 651*7675SEdward.Pilatowicz@Sun.COM } 652*7675SEdward.Pilatowicz@Sun.COM p = strrchr(zpath, '/'); 653*7675SEdward.Pilatowicz@Sun.COM assert(p != NULL); 654*7675SEdward.Pilatowicz@Sun.COM *p = '\0'; 655*7675SEdward.Pilatowicz@Sun.COM continue; 656*7675SEdward.Pilatowicz@Sun.COM } 657*7675SEdward.Pilatowicz@Sun.COM pn_free(&pn_links); 658*7675SEdward.Pilatowicz@Sun.COM 659*7675SEdward.Pilatowicz@Sun.COM /* Place the final result in zpath */ 660*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(tmp, zroot, sizeof (tmp)); 661*7675SEdward.Pilatowicz@Sun.COM (void) strlcat(tmp, zpath, sizeof (tmp)); 662*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(zpath, tmp, sizeof (zpath)); 663*7675SEdward.Pilatowicz@Sun.COM 664*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(zpath, zpath, sizeof (zpath)); 665*7675SEdward.Pilatowicz@Sun.COM dprintf("Pzonepath found zone path (3) '%s'\n", zpath); 666*7675SEdward.Pilatowicz@Sun.COM 667*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, zpath, n); 668*7675SEdward.Pilatowicz@Sun.COM return (s); 669*7675SEdward.Pilatowicz@Sun.COM } 670*7675SEdward.Pilatowicz@Sun.COM 671*7675SEdward.Pilatowicz@Sun.COM char * 672*7675SEdward.Pilatowicz@Sun.COM Pfindobj(struct ps_prochandle *P, const char *path, char *s, size_t n) 673*7675SEdward.Pilatowicz@Sun.COM { 674*7675SEdward.Pilatowicz@Sun.COM int len; 675*7675SEdward.Pilatowicz@Sun.COM 676*7675SEdward.Pilatowicz@Sun.COM dprintf("Pfindobj '%s'\n", path); 677*7675SEdward.Pilatowicz@Sun.COM 678*7675SEdward.Pilatowicz@Sun.COM /* We only deal with absolute paths */ 679*7675SEdward.Pilatowicz@Sun.COM if (path[0] != '/') 680*7675SEdward.Pilatowicz@Sun.COM return (NULL); 681*7675SEdward.Pilatowicz@Sun.COM 682*7675SEdward.Pilatowicz@Sun.COM /* First try to resolve the path to some zone */ 683*7675SEdward.Pilatowicz@Sun.COM if (Pzonepath(P, path, s, n) != NULL) 684*7675SEdward.Pilatowicz@Sun.COM return (s); 685*7675SEdward.Pilatowicz@Sun.COM 686*7675SEdward.Pilatowicz@Sun.COM /* If that fails resolve any lofs links in the path */ 687*7675SEdward.Pilatowicz@Sun.COM if (Plofspath(path, s, n) != NULL) 688*7675SEdward.Pilatowicz@Sun.COM return (s); 689*7675SEdward.Pilatowicz@Sun.COM 690*7675SEdward.Pilatowicz@Sun.COM /* If that fails then just see if the path exists */ 691*7675SEdward.Pilatowicz@Sun.COM if ((len = resolvepath(path, s, n)) > 0) { 692*7675SEdward.Pilatowicz@Sun.COM s[len] = '\0'; 693*7675SEdward.Pilatowicz@Sun.COM return (s); 694*7675SEdward.Pilatowicz@Sun.COM } 695*7675SEdward.Pilatowicz@Sun.COM 696*7675SEdward.Pilatowicz@Sun.COM return (NULL); 697*7675SEdward.Pilatowicz@Sun.COM } 698*7675SEdward.Pilatowicz@Sun.COM 699*7675SEdward.Pilatowicz@Sun.COM char * 700*7675SEdward.Pilatowicz@Sun.COM Pfindmap(struct ps_prochandle *P, map_info_t *mptr, char *s, size_t n) 701*7675SEdward.Pilatowicz@Sun.COM { 702*7675SEdward.Pilatowicz@Sun.COM file_info_t *fptr = mptr->map_file; 703*7675SEdward.Pilatowicz@Sun.COM char buf[PATH_MAX]; 704*7675SEdward.Pilatowicz@Sun.COM int len; 705*7675SEdward.Pilatowicz@Sun.COM 706*7675SEdward.Pilatowicz@Sun.COM /* If it's already been explicity set return that */ 707*7675SEdward.Pilatowicz@Sun.COM if ((fptr != NULL) && (fptr->file_rname != NULL)) { 708*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, fptr->file_rname, n); 709*7675SEdward.Pilatowicz@Sun.COM return (s); 710*7675SEdward.Pilatowicz@Sun.COM } 711*7675SEdward.Pilatowicz@Sun.COM 712*7675SEdward.Pilatowicz@Sun.COM /* If it's the a.out segment, defer to the magical Pexecname() */ 713*7675SEdward.Pilatowicz@Sun.COM if ((P->map_exec == mptr) || 714*7675SEdward.Pilatowicz@Sun.COM (strcmp(mptr->map_pmap.pr_mapname, "a.out") == 0) || 715*7675SEdward.Pilatowicz@Sun.COM ((fptr != NULL) && (fptr->file_lname != NULL) && 716*7675SEdward.Pilatowicz@Sun.COM (strcmp(fptr->file_lname, "a.out") == 0))) { 717*7675SEdward.Pilatowicz@Sun.COM (void) Pexecname(P, buf, sizeof (buf)); 718*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, buf, n); 719*7675SEdward.Pilatowicz@Sun.COM return (s); 720*7675SEdward.Pilatowicz@Sun.COM } 721*7675SEdward.Pilatowicz@Sun.COM 722*7675SEdward.Pilatowicz@Sun.COM /* Try /proc first to get the real object name */ 723*7675SEdward.Pilatowicz@Sun.COM if ((Pstate(P) != PS_DEAD) && (mptr->map_pmap.pr_mapname[0] != '\0')) { 724*7675SEdward.Pilatowicz@Sun.COM (void) snprintf(buf, sizeof (buf), "%s/%d/path/%s", 725*7675SEdward.Pilatowicz@Sun.COM procfs_path, (int)P->pid, mptr->map_pmap.pr_mapname); 726*7675SEdward.Pilatowicz@Sun.COM if ((len = readlink(buf, buf, sizeof (buf))) > 0) { 727*7675SEdward.Pilatowicz@Sun.COM buf[len] = '\0'; 728*7675SEdward.Pilatowicz@Sun.COM (void) Plofspath(buf, buf, sizeof (buf)); 729*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, buf, n); 730*7675SEdward.Pilatowicz@Sun.COM return (s); 731*7675SEdward.Pilatowicz@Sun.COM } 732*7675SEdward.Pilatowicz@Sun.COM } 733*7675SEdward.Pilatowicz@Sun.COM 734*7675SEdward.Pilatowicz@Sun.COM /* 735*7675SEdward.Pilatowicz@Sun.COM * If we couldn't get the name from /proc, take the lname and 736*7675SEdward.Pilatowicz@Sun.COM * try to expand it on the current system to a real object path. 737*7675SEdward.Pilatowicz@Sun.COM */ 738*7675SEdward.Pilatowicz@Sun.COM fptr = mptr->map_file; 739*7675SEdward.Pilatowicz@Sun.COM if ((fptr != NULL) && (fptr->file_lname != NULL)) { 740*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(buf, fptr->file_lname, sizeof (buf)); 741*7675SEdward.Pilatowicz@Sun.COM if (Pfindobj(P, buf, buf, sizeof (buf)) == NULL) 742*7675SEdward.Pilatowicz@Sun.COM return (NULL); 743*7675SEdward.Pilatowicz@Sun.COM (void) strlcpy(s, buf, n); 744*7675SEdward.Pilatowicz@Sun.COM return (s); 745*7675SEdward.Pilatowicz@Sun.COM } 746*7675SEdward.Pilatowicz@Sun.COM 747*7675SEdward.Pilatowicz@Sun.COM return (NULL); 748*7675SEdward.Pilatowicz@Sun.COM } 749