util.c revision 57ef7aa924e4bfdf3118d9b5b4285dfc94b632f3
/*
* 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)));
}