1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Utility functions 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate #include <libintl.h> 33*0Sstevel@tonic-gate #include <stdio.h> 34*0Sstevel@tonic-gate #include <dlfcn.h> 35*0Sstevel@tonic-gate #include <string.h> 36*0Sstevel@tonic-gate #include <errno.h> 37*0Sstevel@tonic-gate #include <alloca.h> 38*0Sstevel@tonic-gate #include "sgs.h" 39*0Sstevel@tonic-gate #include "rtc.h" 40*0Sstevel@tonic-gate #include "_crle.h" 41*0Sstevel@tonic-gate #include "msg.h" 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate /* 45*0Sstevel@tonic-gate * Append an item to the specified list, and return a pointer to the list 46*0Sstevel@tonic-gate * node created. 47*0Sstevel@tonic-gate */ 48*0Sstevel@tonic-gate Listnode * 49*0Sstevel@tonic-gate list_append(List * lst, const void * item) 50*0Sstevel@tonic-gate { 51*0Sstevel@tonic-gate Listnode * lnp; 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate if ((lnp = malloc(sizeof (Listnode))) == (Listnode *)0) 54*0Sstevel@tonic-gate return (0); 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate lnp->data = (void *)item; 57*0Sstevel@tonic-gate lnp->next = NULL; 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate if (lst->head == NULL) 60*0Sstevel@tonic-gate lst->tail = lst->head = lnp; 61*0Sstevel@tonic-gate else { 62*0Sstevel@tonic-gate lst->tail->next = lnp; 63*0Sstevel@tonic-gate lst->tail = lst->tail->next; 64*0Sstevel@tonic-gate } 65*0Sstevel@tonic-gate return (lnp); 66*0Sstevel@tonic-gate } 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * Add an environment string. A list of environment variable descriptors is 70*0Sstevel@tonic-gate * maintained so that duplicate definitions can be caught, the first one wins. 71*0Sstevel@tonic-gate */ 72*0Sstevel@tonic-gate int 73*0Sstevel@tonic-gate addenv(Crle_desc *crle, const char *arg, unsigned int flags) 74*0Sstevel@tonic-gate { 75*0Sstevel@tonic-gate Env_desc *env; 76*0Sstevel@tonic-gate char *str; 77*0Sstevel@tonic-gate size_t varsz, totsz = strlen(arg) + 1; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate /* 80*0Sstevel@tonic-gate * Determine "=" location so as to separated the variable name from 81*0Sstevel@tonic-gate * its value. 82*0Sstevel@tonic-gate */ 83*0Sstevel@tonic-gate if ((str = strchr(arg, '=')) != NULL) { 84*0Sstevel@tonic-gate Listnode * lnp; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate varsz = (size_t)(str - arg); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate /* 89*0Sstevel@tonic-gate * Traverse any existing environment variables to see if we've 90*0Sstevel@tonic-gate * caught a duplicate. 91*0Sstevel@tonic-gate */ 92*0Sstevel@tonic-gate for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) { 93*0Sstevel@tonic-gate if ((env->e_varsz == varsz) && 94*0Sstevel@tonic-gate (strncmp(env->e_str, arg, varsz) == 0)) { 95*0Sstevel@tonic-gate /* 96*0Sstevel@tonic-gate * If the user has already specified this string 97*0Sstevel@tonic-gate * given them a warning, and ignore the new one. 98*0Sstevel@tonic-gate */ 99*0Sstevel@tonic-gate if ((env->e_flags & RTC_ENV_CONFIG) == 0) { 100*0Sstevel@tonic-gate (void) fprintf(stderr, 101*0Sstevel@tonic-gate MSG_INTL(MSG_WARN_ENV), 102*0Sstevel@tonic-gate crle->c_name, (int)varsz, 103*0Sstevel@tonic-gate env->e_str); 104*0Sstevel@tonic-gate return (2); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* 108*0Sstevel@tonic-gate * Otherwise the original string must have been 109*0Sstevel@tonic-gate * retrieved from a config file. In this case 110*0Sstevel@tonic-gate * allow the user to override it. 111*0Sstevel@tonic-gate */ 112*0Sstevel@tonic-gate free((void *)env->e_str); 113*0Sstevel@tonic-gate crle->c_strsize -= env->e_totsz; 114*0Sstevel@tonic-gate crle->c_strsize += totsz; 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate if ((env->e_str = strdup(arg)) == 0) { 117*0Sstevel@tonic-gate int err = errno; 118*0Sstevel@tonic-gate (void) fprintf(stderr, 119*0Sstevel@tonic-gate MSG_INTL(MSG_SYS_MALLOC), 120*0Sstevel@tonic-gate crle->c_name, strerror(err)); 121*0Sstevel@tonic-gate return (0); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate env->e_varsz = varsz; 124*0Sstevel@tonic-gate env->e_totsz = totsz; 125*0Sstevel@tonic-gate env->e_flags &= ~RTC_ENV_CONFIG; 126*0Sstevel@tonic-gate env->e_flags |= flags; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate return (1); 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate } else { 132*0Sstevel@tonic-gate Listnode * lnp; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * Although this is just a plain environment definition (no "=") 136*0Sstevel@tonic-gate * and probably has no effect on ld.so.1 anyway, we might as 137*0Sstevel@tonic-gate * well make sure we're not duplicating the same string. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) { 140*0Sstevel@tonic-gate if (env->e_varsz) 141*0Sstevel@tonic-gate continue; 142*0Sstevel@tonic-gate if (strcmp(env->e_str, arg) == 0) { 143*0Sstevel@tonic-gate if ((env->e_flags & RTC_ENV_CONFIG) == 0) { 144*0Sstevel@tonic-gate (void) fprintf(stderr, 145*0Sstevel@tonic-gate MSG_INTL(MSG_WARN_ENV), 146*0Sstevel@tonic-gate crle->c_name, (int)totsz, 147*0Sstevel@tonic-gate env->e_str); 148*0Sstevel@tonic-gate return (2); 149*0Sstevel@tonic-gate } 150*0Sstevel@tonic-gate env->e_flags &= ~RTC_ENV_CONFIG; 151*0Sstevel@tonic-gate env->e_flags |= flags; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate return (1); 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate varsz = 0; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Allocate a new environment descriptor. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if (((env = malloc(sizeof (Env_desc))) == 0) || 163*0Sstevel@tonic-gate ((env->e_str = strdup(arg)) == 0)) { 164*0Sstevel@tonic-gate int err = errno; 165*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 166*0Sstevel@tonic-gate crle->c_name, strerror(err)); 167*0Sstevel@tonic-gate return (0); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate env->e_varsz = varsz; 170*0Sstevel@tonic-gate env->e_totsz = totsz; 171*0Sstevel@tonic-gate env->e_flags = flags; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if (list_append(&(crle->c_env), env) == 0) 174*0Sstevel@tonic-gate return (0); 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /* 177*0Sstevel@tonic-gate * Update the number of environment variables found, and the string 178*0Sstevel@tonic-gate * table requirement. 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate crle->c_envnum++; 181*0Sstevel@tonic-gate crle->c_strsize += totsz; 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate return (1); 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate * Add a library path. Multiple library paths are concatenated together into a 188*0Sstevel@tonic-gate * colon separated string suitable for runtime processing. These colon 189*0Sstevel@tonic-gate * separated strings can also be passed in as arguments to addlib(), e.g., 190*0Sstevel@tonic-gate * -l /usr/lib:/usr/local/lib. This is enabled to make update easier. 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate int 193*0Sstevel@tonic-gate addlib(Crle_desc *crle, char **lib, const char *args) 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate char *str, *arg; 196*0Sstevel@tonic-gate char *lasts; 197*0Sstevel@tonic-gate size_t tlen = strlen(args) + 1; 198*0Sstevel@tonic-gate const char *colon = MSG_ORIG(MSG_STR_COLON); 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate /* 201*0Sstevel@tonic-gate * Parse the argument for any ":" separated elements. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate str = alloca(tlen); 204*0Sstevel@tonic-gate (void) strcpy(str, args); 205*0Sstevel@tonic-gate arg = str; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate if ((arg = strtok_r(arg, colon, &lasts)) != NULL) { 208*0Sstevel@tonic-gate do { 209*0Sstevel@tonic-gate size_t llen, alen = strlen(arg); 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate if (*lib) { 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * Determine whether this argument exists in the 214*0Sstevel@tonic-gate * existing string buffer. 215*0Sstevel@tonic-gate */ 216*0Sstevel@tonic-gate if (((str = strstr(*lib, arg)) != NULL) && 217*0Sstevel@tonic-gate (((str == *lib) || 218*0Sstevel@tonic-gate (*(str - 1) == *colon)) && 219*0Sstevel@tonic-gate (str += alen) && 220*0Sstevel@tonic-gate ((*str == '\0') || (*str == *colon)))) 221*0Sstevel@tonic-gate continue; 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate llen = strlen(*lib); 224*0Sstevel@tonic-gate tlen = llen + 1; 225*0Sstevel@tonic-gate } else { 226*0Sstevel@tonic-gate /* 227*0Sstevel@tonic-gate * This is the first argument to be added. 228*0Sstevel@tonic-gate */ 229*0Sstevel@tonic-gate llen = 0; 230*0Sstevel@tonic-gate tlen = 0; 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * This is a new string, so add it to the buffer. If 235*0Sstevel@tonic-gate * this is the first occurrence of a string the size is 236*0Sstevel@tonic-gate * simply the size of the string + a trailing null. 237*0Sstevel@tonic-gate * Otherwise the size is the old string + ":" + the 238*0Sstevel@tonic-gate * size of the new string + a trailing null. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate alen += 1; 241*0Sstevel@tonic-gate tlen += alen; 242*0Sstevel@tonic-gate if ((str = realloc((void *)*lib, tlen)) == 0) { 243*0Sstevel@tonic-gate int err = errno; 244*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 245*0Sstevel@tonic-gate crle->c_name, strerror(err)); 246*0Sstevel@tonic-gate return (1); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate if (llen == 0) 249*0Sstevel@tonic-gate (void) strcpy(str, arg); 250*0Sstevel@tonic-gate else { 251*0Sstevel@tonic-gate /* LINTED */ 252*0Sstevel@tonic-gate (void) sprintf(&str[llen], 253*0Sstevel@tonic-gate MSG_ORIG(MSG_FMT_COLON), arg); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate *lib = str; 256*0Sstevel@tonic-gate crle->c_strsize += alen; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate } while ((arg = strtok_r(NULL, colon, &lasts)) != NULL); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate return (0); 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * -f option expansion. Interpret its argument as a numeric or symbolic 267*0Sstevel@tonic-gate * representation of the dldump(3dl) flags. 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate int 270*0Sstevel@tonic-gate dlflags(Crle_desc *crle, const char *arg) 271*0Sstevel@tonic-gate { 272*0Sstevel@tonic-gate int _flags; 273*0Sstevel@tonic-gate char *tok, *_arg; 274*0Sstevel@tonic-gate char *lasts; 275*0Sstevel@tonic-gate const char *separate = MSG_ORIG(MSG_MOD_SEPARATE); 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * Scan the argument looking for allowable tokens. First determine if 279*0Sstevel@tonic-gate * the string is numeric, otherwise try and parse any known flags. 280*0Sstevel@tonic-gate */ 281*0Sstevel@tonic-gate if ((_flags = (int)strtol(arg, (char **)NULL, 0)) != 0) 282*0Sstevel@tonic-gate return (_flags); 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate if ((_arg = malloc(strlen(arg) + 1)) == 0) 285*0Sstevel@tonic-gate return (0); 286*0Sstevel@tonic-gate (void) strcpy(_arg, arg); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if ((tok = strtok_r(_arg, separate, &lasts)) != NULL) { 289*0Sstevel@tonic-gate do { 290*0Sstevel@tonic-gate if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_RELATIVE)) == 0) 291*0Sstevel@tonic-gate _flags |= RTLD_REL_RELATIVE; 292*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_EXEC)) == 0) 293*0Sstevel@tonic-gate _flags |= RTLD_REL_EXEC; 294*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_DEPENDS)) == 0) 295*0Sstevel@tonic-gate _flags |= RTLD_REL_DEPENDS; 296*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_PRELOAD)) == 0) 297*0Sstevel@tonic-gate _flags |= RTLD_REL_PRELOAD; 298*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_SELF)) == 0) 299*0Sstevel@tonic-gate _flags |= RTLD_REL_SELF; 300*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_WEAK)) == 0) 301*0Sstevel@tonic-gate _flags |= RTLD_REL_WEAK; 302*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_ALL)) == 0) 303*0Sstevel@tonic-gate _flags |= RTLD_REL_ALL; 304*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_MEMORY)) == 0) 305*0Sstevel@tonic-gate _flags |= RTLD_MEMORY; 306*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_STRIP)) == 0) 307*0Sstevel@tonic-gate _flags |= RTLD_STRIP; 308*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_NOHEAP)) == 0) 309*0Sstevel@tonic-gate _flags |= RTLD_NOHEAP; 310*0Sstevel@tonic-gate else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_CONFGEN)) == 0) 311*0Sstevel@tonic-gate _flags |= RTLD_CONFGEN; 312*0Sstevel@tonic-gate else { 313*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS), 314*0Sstevel@tonic-gate crle->c_name, tok); 315*0Sstevel@tonic-gate free(_arg); 316*0Sstevel@tonic-gate return (0); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate } while ((tok = strtok_r(NULL, separate, &lasts)) != NULL); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate if (_flags == 0) 321*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS), 322*0Sstevel@tonic-gate crle->c_name, arg); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate free(_arg); 325*0Sstevel@tonic-gate return (_flags); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Internationalization interface for sgsmsg(1l) use. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate const char * 332*0Sstevel@tonic-gate _crle_msg(Msg mid) 333*0Sstevel@tonic-gate { 334*0Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 335*0Sstevel@tonic-gate } 336