OpenSolaris_b135/cmd/sgs/crle/common/util.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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)));
}