xref: /illumos-gate/usr/src/cmd/sgs/crle/common/util.c (revision 8285fe28)
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
addenv(Crle_desc * crle,const char * arg,unsigned int flags)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))) == NULL) ||
135 	    ((env->e_str = strdup(arg)) == NULL)) {
136 		int err = errno;
137 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
138 		    crle->c_name, strerror(err));
139 		free(env);
140 		return (0);
141 	}
142 	env->e_varsz = varsz;
143 	env->e_totsz = totsz;
144 	env->e_flags = flags;
145 
146 	if (aplist_append(&(crle->c_env), env, AL_CNT_CRLE) == NULL)
147 		return (0);
148 
149 	/*
150 	 * Update the number of environment variables found, and the string
151 	 * table requirement.
152 	 */
153 	crle->c_envnum++;
154 	crle->c_strsize += totsz;
155 
156 	return (1);
157 }
158 
159 /*
160  * Add a library path.  Multiple library paths are concatenated together into a
161  * colon separated string suitable for runtime processing.  These colon
162  * separated strings can also be passed in as arguments to addlib(), e.g.,
163  * -l /usr/lib:/usr/local/lib.  This is enabled to make update easier.
164  */
165 int
addlib(Crle_desc * crle,char ** lib,const char * args)166 addlib(Crle_desc *crle, char **lib, const char *args)
167 {
168 	char		*str, *arg;
169 	char		*lasts;
170 	size_t		tlen = strlen(args) + 1;
171 	const char	*colon = MSG_ORIG(MSG_STR_COLON);
172 
173 	/*
174 	 * Parse the argument for any ":" separated elements.
175 	 */
176 	str = alloca(tlen);
177 	(void) strcpy(str, args);
178 	arg = str;
179 
180 	if ((arg = strtok_r(arg, colon, &lasts)) != NULL) {
181 		do {
182 			size_t	llen, alen = strlen(arg);
183 
184 			if (*lib) {
185 				/*
186 				 * Determine whether this argument exists in the
187 				 * existing string buffer.
188 				 */
189 				if (((str = strstr(*lib, arg)) != NULL) &&
190 				    (((str == *lib) ||
191 				    (*(str - 1) == *colon)) &&
192 				    (str += alen) &&
193 				    ((*str == '\0') || (*str == *colon))))
194 					continue;
195 
196 				llen = strlen(*lib);
197 				tlen = llen + 1;
198 			} else {
199 				/*
200 				 * This is the first argument to be added.
201 				 */
202 				llen = 0;
203 				tlen = 0;
204 			}
205 
206 			/*
207 			 * This is a new string, so add it to the buffer.  If
208 			 * this is the first occurrence of a string the size is
209 			 * simply the size of the string + a trailing null.
210 			 * Otherwise the size is the old string + ":" + the
211 			 * size of the new string + a trailing null.
212 			 */
213 			alen += 1;
214 			tlen += alen;
215 			if ((str = realloc((void *)*lib, tlen)) == 0) {
216 				int err = errno;
217 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
218 				    crle->c_name, strerror(err));
219 				return (1);
220 			}
221 			if (llen == 0)
222 				(void) strcpy(str, arg);
223 			else {
224 				/* LINTED */
225 				(void) sprintf(&str[llen],
226 				    MSG_ORIG(MSG_FMT_COLON), arg);
227 			}
228 			*lib = str;
229 			crle->c_strsize += alen;
230 
231 		} while ((arg = strtok_r(NULL, colon, &lasts)) != NULL);
232 	}
233 
234 	return (0);
235 }
236 
237 
238 /*
239  * -f option expansion.  Interpret its argument as a numeric or symbolic
240  * representation of the dldump(3dl) flags.
241  */
242 int
dlflags(Crle_desc * crle,const char * arg)243 dlflags(Crle_desc *crle, const char *arg)
244 {
245 	int		_flags;
246 	char		*tok, *_arg;
247 	char		*lasts;
248 	const char	*separate = MSG_ORIG(MSG_MOD_SEPARATE);
249 
250 	/*
251 	 * Scan the argument looking for allowable tokens.  First determine if
252 	 * the string is numeric, otherwise try and parse any known flags.
253 	 */
254 	if ((_flags = (int)strtol(arg, (char **)NULL, 0)) != 0)
255 		return (_flags);
256 
257 	if ((_arg = malloc(strlen(arg) + 1)) == 0)
258 		return (0);
259 	(void) strcpy(_arg, arg);
260 
261 	if ((tok = strtok_r(_arg, separate, &lasts)) != NULL) {
262 		/* BEGIN CSTYLED */
263 		do {
264 		    if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_RELATIVE)) == 0)
265 			_flags |= RTLD_REL_RELATIVE;
266 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_EXEC)) == 0)
267 			_flags |= RTLD_REL_EXEC;
268 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_DEPENDS)) == 0)
269 			_flags |= RTLD_REL_DEPENDS;
270 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_PRELOAD)) == 0)
271 			_flags |= RTLD_REL_PRELOAD;
272 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_SELF)) == 0)
273 			_flags |= RTLD_REL_SELF;
274 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_WEAK)) == 0)
275 			_flags |= RTLD_REL_WEAK;
276 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_ALL)) == 0)
277 			_flags |= RTLD_REL_ALL;
278 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_MEMORY)) == 0)
279 			_flags |= RTLD_MEMORY;
280 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_STRIP)) == 0)
281 			_flags |= RTLD_STRIP;
282 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_NOHEAP)) == 0)
283 			_flags |= RTLD_NOHEAP;
284 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_CONFGEN)) == 0)
285 			_flags |= RTLD_CONFGEN;
286 		    else {
287 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS),
288 			    crle->c_name, tok);
289 			free(_arg);
290 			return (0);
291 		    }
292 		} while ((tok = strtok_r(NULL, separate, &lasts)) != NULL);
293 		/* END CSTYLED */
294 	}
295 	if (_flags == 0)
296 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS),
297 		    crle->c_name, arg);
298 
299 	free(_arg);
300 	return (_flags);
301 }
302 
303 /*
304  * Internationalization interface for sgsmsg(1l) use.
305  */
306 const char *
_crle_msg(Msg mid)307 _crle_msg(Msg mid)
308 {
309 	return (gettext(MSG_ORIG(mid)));
310 }
311