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