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