dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / abi / apptrace / common / abienv.c
blob2d5fab34ede6df04c21bf5a53e34d2964f0e9d54
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <dlfcn.h>
35 #include <errno.h>
36 #include <fnmatch.h>
37 #include <apptrace.h>
38 #include <libintl.h>
39 #include "abienv.h"
41 static char const *strdup_sym = "strdup";
42 static char const *malloc_sym = "malloc";
43 static char const *comma = ",";
45 static void
46 bugout(char const *call)
48 (void) fprintf(stderr,
49 dgettext(TEXT_DOMAIN, "apptrace: %s failed\n"),
50 call);
51 exit(EXIT_FAILURE);
54 void
55 build_env_list(Liblist **list, char const *env)
57 char *envstr;
58 char *tok;
60 if ((envstr = getenv(env)) == NULL)
61 return;
63 if ((envstr = strdup(envstr)) == NULL)
64 bugout(strdup_sym);
66 tok = strtok(envstr, comma);
67 while (tok != NULL) {
68 Liblist *lp;
70 if ((lp = malloc(sizeof (Liblist))) == NULL)
71 bugout(malloc_sym);
73 lp->l_libname = tok;
74 lp->l_next = *list;
75 *list = lp;
76 tok = strtok(NULL, comma);
80 void
81 build_env_list1(Liblist **list, Liblist **listend, const char *env)
83 char *envstr;
84 char *tok;
86 if ((envstr = getenv(env)) == NULL)
87 return;
90 * It is possible that we have a single file name,
91 * in which case the subseqent loop will do nothing
93 if (strchr(envstr, ',') == NULL) {
94 appendlist(list, listend, envstr, 1);
95 return;
98 if ((envstr = strdup(envstr)) == NULL)
99 bugout(strdup_sym);
101 tok = strtok(envstr, comma);
102 while (tok != NULL) {
103 appendlist(list, listend, tok, 1);
104 tok = strtok(NULL, comma);
106 free(envstr);
109 void
110 env_to_intlist(Intlist **list, char const *env)
112 char *envstr;
113 char *tok;
115 if ((envstr = getenv(env)) == NULL)
116 return;
118 if ((envstr = strdup(envstr)) == NULL)
119 bugout(strdup_sym);
121 for (tok = strtok(envstr, comma);
122 tok != NULL;
123 tok = strtok(NULL, comma)) {
125 Intlist *ip;
127 if ((ip = malloc(sizeof (Intlist))) == NULL)
128 bugout(malloc_sym);
130 if ((ip->i_name = strdup(tok)) == NULL)
131 bugout(strdup_sym);
133 ip->i_next = *list;
134 *list = ip;
136 free(envstr);
139 void
140 appendlist(Liblist **list, Liblist **listend, const char *name, int fatal)
142 Liblist *lp;
143 void *handle;
145 if (access(name, R_OK)) {
146 if (fatal) {
147 (void) fprintf(stderr,
148 dgettext(TEXT_DOMAIN,
149 "apptrace: %s: %s\n"),
150 name,
151 strerror(errno));
152 exit(EXIT_FAILURE);
154 return;
157 if ((handle = dlopen(name, RTLD_LAZY)) == NULL) {
158 if (fatal) {
159 (void) fprintf(stderr,
160 dgettext(TEXT_DOMAIN,
161 "apptrace: dlopen on %s failed: %s\n"),
162 name,
163 dlerror());
164 exit(EXIT_FAILURE);
166 return;
169 /* OK, so now add it to the end of the list */
170 if ((lp = malloc(sizeof (Liblist))) == NULL)
171 bugout(malloc_sym);
173 if ((lp->l_libname = strdup(name)) == NULL)
174 bugout(strdup_sym);
175 lp->l_handle = handle;
176 lp->l_next = NULL;
177 if (*listend)
178 (*listend)->l_next = lp;
179 if (*list == NULL)
180 *list = lp;
181 *listend = lp;
185 * Called abibasename() to avoid clash with basename(3C)
186 * Incidentally, basename(3C) is destructive which is why
187 * we are not using it instead.
189 char *
190 abibasename(const char *str)
192 char *p;
194 if ((p = strrchr(str, '/')) != NULL)
195 return (p + 1);
196 else
197 return ((char *)str);
200 Liblist *
201 check_list(Liblist *list, char const *str)
203 char *basename1, *basename2, *p1, *p2;
204 Liblist *ret = NULL;
206 if (list == NULL)
207 return (NULL);
209 if ((basename2 = strdup(abibasename(str))) == NULL)
210 bugout(strdup_sym);
211 if ((p2 = strchr(basename2, '.')) != NULL)
212 *p2 = '\0';
214 for (; list; list = list->l_next) {
215 /* Lose the dirname */
216 if ((basename1 = strdup(abibasename(list->l_libname))) == NULL)
217 bugout(strdup_sym);
218 /* Lose the suffix */
219 if ((p1 = strchr(basename1, '.')) != NULL)
220 *p1 = '\0';
221 if (fnmatch(basename1, basename2, 0) == 0) {
222 ret = list;
223 free(basename1);
224 break;
226 free(basename1);
229 free(basename2);
230 return (ret);
234 check_intlist(Intlist *list, char const *iface)
236 if (list == NULL)
237 return (0);
239 for (; list != NULL; list = list->i_next) {
240 if (fnmatch(list->i_name, iface, 0) == 0)
241 return (1);
244 return (0);
247 char *
248 checkenv(char const *env)
250 char *envstr;
252 if ((envstr = getenv(env)) == NULL)
253 return (NULL);
254 while (*envstr == ' ')
255 envstr++;
256 if (*envstr == '\0')
257 return (NULL);
258 return (envstr);
262 build_interceptor_path(char *buf, size_t l, char const *path)
264 char *p, *t, *f;
265 #if defined(_LP64)
266 char *m;
267 #endif
268 int ret;
270 /* Duplicate the path */
271 if ((p = strdup(path)) == NULL)
272 bugout(strdup_sym);
274 /* Find the last slash, if there ain't one bug out */
275 if ((t = strrchr(p, '/')) == NULL) {
276 ret = 0;
277 goto done;
281 * Wack the slash to a null byte.
282 * Thus if we got:
283 * /A/B/C/D.so.1
284 * p now points to /A/B/C
285 * f is set to point to D.so.1
287 *t = '\0';
288 f = ++t;
290 #if defined(_LP64)
292 * As above except that in LP64 (for sparc) we'll get:
293 * /A/B/C/sparcv9/D.so.1
294 * thus p now points to:
295 * /A/B/C/sparcv9
296 * so we repeat the wack so that we get:
297 * /A/B/C
298 * and retain a pointer, m, to the machine dependent portion.
300 if ((t = strrchr(p, '/')) == NULL) {
301 ret = 0;
302 goto done;
304 *t = '\0';
305 m = ++t;
308 * Now we can build a path name.
309 * This path is only a guess that'll be checked later in appendlist().
310 * Some system libraries, like libc.so.1, reside in /lib while their
311 * corresponding abi_* counterparts reside in /usr/lib. The same is
312 * true for libraries like libc_psr.so.1 that reside in /platform
313 * rather than /usr/platform. To deal with this, we check whether
314 * the file in the direct path name we generate exists, and if not,
315 * we prepend "/usr" to it. This handles all existing cases.
317 ret = snprintf(buf, l, "%s/abi/%s/abi_%s", p, m, f);
318 if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
319 ret = snprintf(buf, l, "/usr%s/abi/%s/abi_%s", p, m, f);
320 #else
321 ret = snprintf(buf, l, "%s/abi/abi_%s", p, f);
322 if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
323 ret = snprintf(buf, l, "/usr%s/abi/abi_%s", p, f);
324 #endif
326 done:
327 free(p);
328 return (ret);