xref: /illumos-gate/usr/src/cmd/sgs/crle/common/util.c (revision fcf3ce44)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Utility functions
31  */
32 #include <libintl.h>
33 #include <stdio.h>
34 #include <dlfcn.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <alloca.h>
38 #include "sgs.h"
39 #include "rtc.h"
40 #include "_crle.h"
41 #include "msg.h"
42 
43 
44 /*
45  * Append an item to the specified list, and return a pointer to the list
46  * node created.
47  */
48 Listnode *
49 list_append(List * lst, const void * item)
50 {
51 	Listnode *	lnp;
52 
53 	if ((lnp = malloc(sizeof (Listnode))) == (Listnode *)0)
54 		return (0);
55 
56 	lnp->data = (void *)item;
57 	lnp->next = NULL;
58 
59 	if (lst->head == NULL)
60 		lst->tail = lst->head = lnp;
61 	else {
62 		lst->tail->next = lnp;
63 		lst->tail = lst->tail->next;
64 	}
65 	return (lnp);
66 }
67 
68 /*
69  * Add an environment string.  A list of environment variable descriptors is
70  * maintained so that duplicate definitions can be caught, the first one wins.
71  */
72 int
73 addenv(Crle_desc *crle, const char *arg, unsigned int flags)
74 {
75 	Env_desc	*env;
76 	char		*str;
77 	size_t		varsz, totsz = strlen(arg) + 1;
78 
79 	/*
80 	 * Determine "=" location so as to separated the variable name from
81 	 * its value.
82 	 */
83 	if ((str = strchr(arg, '=')) != NULL) {
84 		Listnode *	lnp;
85 
86 		varsz = (size_t)(str - arg);
87 
88 		/*
89 		 * Traverse any existing environment variables to see if we've
90 		 * caught a duplicate.
91 		 */
92 		for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) {
93 			if ((env->e_varsz == varsz) &&
94 			    (strncmp(env->e_str, arg, varsz) == 0)) {
95 				/*
96 				 * If the user has already specified this string
97 				 * given them a warning, and ignore the new one.
98 				 */
99 				if ((env->e_flags & RTC_ENV_CONFIG) == 0) {
100 					(void) fprintf(stderr,
101 					    MSG_INTL(MSG_WARN_ENV),
102 					    crle->c_name, (int)varsz,
103 					    env->e_str);
104 					return (2);
105 				}
106 
107 				/*
108 				 * Otherwise the original string must have been
109 				 * retrieved from a config file.  In this case
110 				 * allow the user to override it.
111 				 */
112 				free((void *)env->e_str);
113 				crle->c_strsize -= env->e_totsz;
114 				crle->c_strsize += totsz;
115 
116 				if ((env->e_str = strdup(arg)) == 0) {
117 					int err = errno;
118 					(void) fprintf(stderr,
119 					    MSG_INTL(MSG_SYS_MALLOC),
120 					    crle->c_name, strerror(err));
121 					return (0);
122 				}
123 				env->e_varsz = varsz;
124 				env->e_totsz = totsz;
125 				env->e_flags &= ~RTC_ENV_CONFIG;
126 				env->e_flags |= flags;
127 
128 				return (1);
129 			}
130 		}
131 	} else {
132 		Listnode *	lnp;
133 
134 		/*
135 		 * Although this is just a plain environment definition (no "=")
136 		 * and probably has no effect on ld.so.1 anyway, we might as
137 		 * well make sure we're not duplicating the same string.
138 		 */
139 		for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) {
140 			if (env->e_varsz)
141 				continue;
142 			if (strcmp(env->e_str, arg) == 0) {
143 				if ((env->e_flags & RTC_ENV_CONFIG) == 0) {
144 					(void) fprintf(stderr,
145 					    MSG_INTL(MSG_WARN_ENV),
146 					    crle->c_name, (int)totsz,
147 					    env->e_str);
148 					return (2);
149 				}
150 				env->e_flags &= ~RTC_ENV_CONFIG;
151 				env->e_flags |= flags;
152 
153 				return (1);
154 			}
155 		}
156 		varsz = 0;
157 	}
158 
159 	/*
160 	 * Allocate a new environment descriptor.
161 	 */
162 	if (((env = malloc(sizeof (Env_desc))) == 0) ||
163 	    ((env->e_str = strdup(arg)) == 0)) {
164 		int err = errno;
165 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
166 		    crle->c_name, strerror(err));
167 		return (0);
168 	}
169 	env->e_varsz = varsz;
170 	env->e_totsz = totsz;
171 	env->e_flags = flags;
172 
173 	if (list_append(&(crle->c_env), env) == 0)
174 		return (0);
175 
176 	/*
177 	 * Update the number of environment variables found, and the string
178 	 * table requirement.
179 	 */
180 	crle->c_envnum++;
181 	crle->c_strsize += totsz;
182 
183 	return (1);
184 }
185 
186 /*
187  * Add a library path.  Multiple library paths are concatenated together into a
188  * colon separated string suitable for runtime processing.  These colon
189  * separated strings can also be passed in as arguments to addlib(), e.g.,
190  * -l /usr/lib:/usr/local/lib.  This is enabled to make update easier.
191  */
192 int
193 addlib(Crle_desc *crle, char **lib, const char *args)
194 {
195 	char		*str, *arg;
196 	char		*lasts;
197 	size_t		tlen = strlen(args) + 1;
198 	const char	*colon = MSG_ORIG(MSG_STR_COLON);
199 
200 	/*
201 	 * Parse the argument for any ":" separated elements.
202 	 */
203 	str = alloca(tlen);
204 	(void) strcpy(str, args);
205 	arg = str;
206 
207 	if ((arg = strtok_r(arg, colon, &lasts)) != NULL) {
208 		do {
209 			size_t	llen, alen = strlen(arg);
210 
211 			if (*lib) {
212 				/*
213 				 * Determine whether this argument exists in the
214 				 * existing string buffer.
215 				 */
216 				if (((str = strstr(*lib, arg)) != NULL) &&
217 				    (((str == *lib) ||
218 				    (*(str - 1) == *colon)) &&
219 				    (str += alen) &&
220 				    ((*str == '\0') || (*str == *colon))))
221 					continue;
222 
223 				llen = strlen(*lib);
224 				tlen = llen + 1;
225 			} else {
226 				/*
227 				 * This is the first argument to be added.
228 				 */
229 				llen = 0;
230 				tlen = 0;
231 			}
232 
233 			/*
234 			 * This is a new string, so add it to the buffer.  If
235 			 * this is the first occurrence of a string the size is
236 			 * simply the size of the string + a trailing null.
237 			 * Otherwise the size is the old string + ":" + the
238 			 * size of the new string + a trailing null.
239 			 */
240 			alen += 1;
241 			tlen += alen;
242 			if ((str = realloc((void *)*lib, tlen)) == 0) {
243 				int err = errno;
244 				(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC),
245 				    crle->c_name, strerror(err));
246 				return (1);
247 			}
248 			if (llen == 0)
249 				(void) strcpy(str, arg);
250 			else {
251 				/* LINTED */
252 				(void) sprintf(&str[llen],
253 				    MSG_ORIG(MSG_FMT_COLON), arg);
254 			}
255 			*lib = str;
256 			crle->c_strsize += alen;
257 
258 		} while ((arg = strtok_r(NULL, colon, &lasts)) != NULL);
259 	}
260 
261 	return (0);
262 }
263 
264 
265 /*
266  * -f option expansion.  Interpret its argument as a numeric or symbolic
267  * representation of the dldump(3dl) flags.
268  */
269 int
270 dlflags(Crle_desc *crle, const char *arg)
271 {
272 	int		_flags;
273 	char		*tok, *_arg;
274 	char		*lasts;
275 	const char	*separate = MSG_ORIG(MSG_MOD_SEPARATE);
276 
277 	/*
278 	 * Scan the argument looking for allowable tokens.  First determine if
279 	 * the string is numeric, otherwise try and parse any known flags.
280 	 */
281 	if ((_flags = (int)strtol(arg, (char **)NULL, 0)) != 0)
282 		return (_flags);
283 
284 	if ((_arg = malloc(strlen(arg) + 1)) == 0)
285 		return (0);
286 	(void) strcpy(_arg, arg);
287 
288 	if ((tok = strtok_r(_arg, separate, &lasts)) != NULL) {
289 		do {
290 		    if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_RELATIVE)) == 0)
291 			_flags |= RTLD_REL_RELATIVE;
292 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_EXEC)) == 0)
293 			_flags |= RTLD_REL_EXEC;
294 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_DEPENDS)) == 0)
295 			_flags |= RTLD_REL_DEPENDS;
296 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_PRELOAD)) == 0)
297 			_flags |= RTLD_REL_PRELOAD;
298 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_SELF)) == 0)
299 			_flags |= RTLD_REL_SELF;
300 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_WEAK)) == 0)
301 			_flags |= RTLD_REL_WEAK;
302 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_ALL)) == 0)
303 			_flags |= RTLD_REL_ALL;
304 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_MEMORY)) == 0)
305 			_flags |= RTLD_MEMORY;
306 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_STRIP)) == 0)
307 			_flags |= RTLD_STRIP;
308 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_NOHEAP)) == 0)
309 			_flags |= RTLD_NOHEAP;
310 		    else if (strcmp(tok, MSG_ORIG(MSG_MOD_REL_CONFGEN)) == 0)
311 			_flags |= RTLD_CONFGEN;
312 		    else {
313 			(void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS),
314 			    crle->c_name, tok);
315 			free(_arg);
316 			return (0);
317 		    }
318 		} while ((tok = strtok_r(NULL, separate, &lasts)) != NULL);
319 	}
320 	if (_flags == 0)
321 		(void) fprintf(stderr, MSG_INTL(MSG_ARG_FLAGS),
322 		    crle->c_name, arg);
323 
324 	free(_arg);
325 	return (_flags);
326 }
327 
328 /*
329  * Internationalization interface for sgsmsg(1l) use.
330  */
331 const char *
332 _crle_msg(Msg mid)
333 {
334 	return (gettext(MSG_ORIG(mid)));
335 }
336