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