/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Utility functions */ #include <libintl.h> #include <stdio.h> #include <dlfcn.h> #include <string.h> #include <errno.h> #include <alloca.h> #include "sgs.h" #include "rtc.h" #include "_crle.h" #include "msg.h" /* * Add an environment string. A list of environment variable descriptors is * maintained so that duplicate definitions can be caught, the first one wins. */ int addenv(Crle_desc *crle, const char *arg, unsigned int flags) { Env_desc *env; char *str; size_t varsz, totsz = strlen(arg) + 1; /* * Determine "=" location so as to separated the variable name from * its value. */ if ((str = strchr(arg, '=')) != NULL) { Aliste idx; varsz = (size_t)(str - arg); /* * Traverse any existing environment variables to see if we've * caught a duplicate. */ for (APLIST_TRAVERSE(crle->c_env, idx, env)) { if ((env->e_varsz == varsz) && (strncmp(env->e_str, arg, varsz) == 0)) { /* * If the user has already specified this string * given them a warning, and ignore the new one. */ if ((env->e_flags & RTC_ENV_CONFIG) == 0) { (void) fprintf(stderr, MSG_INTL(MSG_WARN_ENV), crle->c_name, (int)varsz, env->e_str); return (2); } /* * Otherwise the original string must have been * retrieved from a config file. In this case * allow the user to override it. */ free((void *)env->e_str); crle->c_strsize -= env->e_totsz; crle->c_strsize += totsz; if ((env->e_str = strdup(arg)) == 0) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), crle->c_name, strerror(err)); return (0); } env->e_varsz = varsz; env->e_totsz = totsz; env->e_flags &= ~RTC_ENV_CONFIG; env->e_flags |= flags; return (1); } } } else { Aliste idx; /* * Although this is just a plain environment definition (no "=") * and probably has no effect on ld.so.1 anyway, we might as * well make sure we're not duplicating the same string. */ for (APLIST_TRAVERSE(crle->c_env, idx, env)) { if (env->e_varsz) continue; if (strcmp(env->e_str, arg) == 0) { if ((env->e_flags & RTC_ENV_CONFIG) == 0) { (void) fprintf(stderr, MSG_INTL(MSG_WARN_ENV), crle->c_name, (int)totsz, env->e_str); return (2); } env->e_flags &= ~RTC_ENV_CONFIG; env->e_flags |= flags; return (1); } } varsz = 0; } /* * Allocate a new environment descriptor. */ if (((env = malloc(sizeof (Env_desc))) == 0) || ((env->e_str = strdup(arg)) == 0)) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), crle->c_name, strerror(err)); return (0); } env->e_varsz = varsz; env->e_totsz = totsz; env->e_flags = flags; if (aplist_append(&(crle->c_env), env, AL_CNT_CRLE) == NULL) return (0); /* * Update the number of environment variables found, and the string * table requirement. */ crle->c_envnum++; crle->c_strsize += totsz; return (1); } /* * Add a library path. Multiple library paths are concatenated together into a * colon separated string suitable for runtime processing. These colon * separated strings can also be passed in as arguments to addlib(), e.g., * -l /usr/lib:/usr/local/lib. This is enabled to make update easier. */ int addlib(Crle_desc *crle, char **lib, const char *args) { char *str, *arg; char *lasts; size_t tlen = strlen(args) + 1; const char *colon = MSG_ORIG(MSG_STR_COLON); /* * Parse the argument for any ":" separated elements. */ str = alloca(tlen); (void) strcpy(str, args); arg = str; if ((arg = strtok_r(arg, colon, &lasts)) != NULL) { do { size_t llen, alen = strlen(arg); if (*lib) { /* * Determine whether this argument exists in the * existing string buffer. */ if (((str = strstr(*lib, arg)) != NULL) && (((str == *lib) || (*(str - 1) == *colon)) && (str += alen) && ((*str == '\0') || (*str == *colon)))) continue; llen = strlen(*lib); tlen = llen + 1; } else { /* * This is the first argument to be added. */ llen = 0; tlen = 0; } /* * This is a new string, so add it to the buffer. If * this is the first occurrence of a string the size is * simply the size of the string + a trailing null. * Otherwise the size is the old string + ":" + the * size of the new string + a trailing null. */ alen += 1; tlen += alen; if ((str = realloc((void *)*lib, tlen)) == 0) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), crle->c_name, strerror(err)); return (1); } if (llen == 0) (void) strcpy(str, arg); else { /* LINTED */ (void) sprintf(&str[llen], MSG_ORIG(MSG_FMT_COLON), arg); } *lib = str; crle->c_strsize += alen; } while ((arg = strtok_r(NULL, colon, &lasts)) != NULL); } return (0); } /* * -f option expansion. Interpret its argument as a numeric or symbolic * representation of the dldump(3dl) flags. */ int dlflags(Crle_desc *crle, const char *arg) { int _flags; char *tok, *_arg; char *lasts; const char *separate = MSG_ORIG(MSG_MOD_SEPARATE); /* * Scan the argument looking for allowable tokens. First determine if * the string is numeric, otherwise try and parse any known flags. */ if ((_flags = (int)strtol(arg, (char **)NULL, 0)) != 0) return (_flags); if ((_arg = malloc(strlen(arg) + 1)) == 0) return (0); (void) strcpy(_arg, arg); if ((tok = strtok_r(_arg, separate, &lasts)) != NULL) { /* BEGIN CSTYLED */ do { if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_RELATIVE)) == 0) _flags |= RTLD_REL_RELATIVE; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_EXEC)) == 0) _flags |= RTLD_REL_EXEC; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_DEPENDS)) == 0) _flags |= RTLD_REL_DEPENDS; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_PRELOAD)) == 0) _flags |= RTLD_REL_PRELOAD; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_SELF)) == 0) _flags |= RTLD_REL_SELF; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_WEAK)) == 0) _flags |= RTLD_REL_WEAK; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_ALL)) == 0) _flags |= RTLD_REL_ALL; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_MEMORY)) == 0) _flags |= RTLD_MEMORY; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_STRIP)) == 0) _flags |= RTLD_STRIP; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_NOHEAP)) == 0) _flags |= RTLD_NOHEAP; else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_CONFGEN)) == 0) _flags |= RTLD_CONFGEN; else { (void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS), crle->c_name, tok); free(_arg); return (0); } } while ((tok = strtok_r(NULL, separate, &lasts)) != NULL); /* END CSTYLED */ } if (_flags == 0) (void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS), crle->c_name, arg); free(_arg); return (_flags); } /* * Internationalization interface for sgsmsg(1l) use. */ const char * _crle_msg(Msg mid) { return (gettext(MSG_ORIG(mid))); }