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