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