1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
28*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
29*7c478bd9Sstevel@tonic-gate #include <unistd.h>
30*7c478bd9Sstevel@tonic-gate #include <string.h>
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <dlfcn.h>
33*7c478bd9Sstevel@tonic-gate #include <errno.h>
34*7c478bd9Sstevel@tonic-gate #include <fnmatch.h>
35*7c478bd9Sstevel@tonic-gate #include <apptrace.h>
36*7c478bd9Sstevel@tonic-gate #include <libintl.h>
37*7c478bd9Sstevel@tonic-gate #include "abienv.h"
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate static char const *strdup_sym = "strdup";
40*7c478bd9Sstevel@tonic-gate static char const *malloc_sym = "malloc";
41*7c478bd9Sstevel@tonic-gate static char const *comma = ",";
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate static void
bugout(char const * call)44*7c478bd9Sstevel@tonic-gate bugout(char const *call)
45*7c478bd9Sstevel@tonic-gate {
46*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
47*7c478bd9Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "apptrace: %s failed\n"),
48*7c478bd9Sstevel@tonic-gate 			call);
49*7c478bd9Sstevel@tonic-gate 	exit(EXIT_FAILURE);
50*7c478bd9Sstevel@tonic-gate }
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate void
build_env_list(Liblist ** list,char const * env)53*7c478bd9Sstevel@tonic-gate build_env_list(Liblist **list, char const *env)
54*7c478bd9Sstevel@tonic-gate {
55*7c478bd9Sstevel@tonic-gate 	char *envstr;
56*7c478bd9Sstevel@tonic-gate 	char *tok;
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	if ((envstr = getenv(env)) == NULL)
59*7c478bd9Sstevel@tonic-gate 		return;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	if ((envstr = strdup(envstr)) == NULL)
62*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	tok = strtok(envstr, comma);
65*7c478bd9Sstevel@tonic-gate 	while (tok != NULL) {
66*7c478bd9Sstevel@tonic-gate 		Liblist *lp;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 		if ((lp = malloc(sizeof (Liblist))) == NULL)
69*7c478bd9Sstevel@tonic-gate 			bugout(malloc_sym);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 		lp->l_libname = tok;
72*7c478bd9Sstevel@tonic-gate 		lp->l_next = *list;
73*7c478bd9Sstevel@tonic-gate 		*list = lp;
74*7c478bd9Sstevel@tonic-gate 		tok = strtok(NULL, comma);
75*7c478bd9Sstevel@tonic-gate 	}
76*7c478bd9Sstevel@tonic-gate }
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate void
build_env_list1(Liblist ** list,Liblist ** listend,const char * env)79*7c478bd9Sstevel@tonic-gate build_env_list1(Liblist **list, Liblist **listend, const char *env)
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	char *envstr;
82*7c478bd9Sstevel@tonic-gate 	char *tok;
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate 	if ((envstr = getenv(env)) == NULL)
85*7c478bd9Sstevel@tonic-gate 		return;
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	/*
88*7c478bd9Sstevel@tonic-gate 	 * It is possible that we have a single file name,
89*7c478bd9Sstevel@tonic-gate 	 * in which case the subseqent loop will do nothing
90*7c478bd9Sstevel@tonic-gate 	 */
91*7c478bd9Sstevel@tonic-gate 	if (strchr(envstr, ',') == NULL) {
92*7c478bd9Sstevel@tonic-gate 		appendlist(list, listend, envstr, 1);
93*7c478bd9Sstevel@tonic-gate 		return;
94*7c478bd9Sstevel@tonic-gate 	}
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	if ((envstr = strdup(envstr)) == NULL)
97*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	tok = strtok(envstr, comma);
100*7c478bd9Sstevel@tonic-gate 	while (tok != NULL) {
101*7c478bd9Sstevel@tonic-gate 		appendlist(list, listend, tok, 1);
102*7c478bd9Sstevel@tonic-gate 		tok = strtok(NULL, comma);
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 	free(envstr);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate void
env_to_intlist(Intlist ** list,char const * env)108*7c478bd9Sstevel@tonic-gate env_to_intlist(Intlist **list, char const *env)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	char *envstr;
111*7c478bd9Sstevel@tonic-gate 	char *tok;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if ((envstr = getenv(env)) == NULL)
114*7c478bd9Sstevel@tonic-gate 		return;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if ((envstr = strdup(envstr)) == NULL)
117*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	for (tok = strtok(envstr, comma);
120*7c478bd9Sstevel@tonic-gate 	    tok != NULL;
121*7c478bd9Sstevel@tonic-gate 	    tok = strtok(NULL, comma)) {
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 		Intlist *ip;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 		if ((ip = malloc(sizeof (Intlist))) == NULL)
126*7c478bd9Sstevel@tonic-gate 			bugout(malloc_sym);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 		if ((ip->i_name = strdup(tok)) == NULL)
129*7c478bd9Sstevel@tonic-gate 			bugout(strdup_sym);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 		ip->i_next = *list;
132*7c478bd9Sstevel@tonic-gate 		*list = ip;
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	free(envstr);
135*7c478bd9Sstevel@tonic-gate }
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate void
appendlist(Liblist ** list,Liblist ** listend,const char * name,int fatal)138*7c478bd9Sstevel@tonic-gate appendlist(Liblist **list, Liblist **listend, const char *name, int fatal)
139*7c478bd9Sstevel@tonic-gate {
140*7c478bd9Sstevel@tonic-gate 	Liblist	*lp;
141*7c478bd9Sstevel@tonic-gate 	void	*handle;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	if (access(name, R_OK)) {
144*7c478bd9Sstevel@tonic-gate 		if (fatal) {
145*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
146*7c478bd9Sstevel@tonic-gate 					dgettext(TEXT_DOMAIN,
147*7c478bd9Sstevel@tonic-gate 						"apptrace: %s: %s\n"),
148*7c478bd9Sstevel@tonic-gate 					name,
149*7c478bd9Sstevel@tonic-gate 					strerror(errno));
150*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
151*7c478bd9Sstevel@tonic-gate 		}
152*7c478bd9Sstevel@tonic-gate 		return;
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if ((handle = dlopen(name, RTLD_LAZY)) == NULL) {
156*7c478bd9Sstevel@tonic-gate 		if (fatal) {
157*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
158*7c478bd9Sstevel@tonic-gate 					dgettext(TEXT_DOMAIN,
159*7c478bd9Sstevel@tonic-gate 					"apptrace: dlopen on %s failed: %s\n"),
160*7c478bd9Sstevel@tonic-gate 					name,
161*7c478bd9Sstevel@tonic-gate 					dlerror());
162*7c478bd9Sstevel@tonic-gate 			exit(EXIT_FAILURE);
163*7c478bd9Sstevel@tonic-gate 		}
164*7c478bd9Sstevel@tonic-gate 		return;
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/* OK, so now add it to the end of the list */
168*7c478bd9Sstevel@tonic-gate 	if ((lp = malloc(sizeof (Liblist))) == NULL)
169*7c478bd9Sstevel@tonic-gate 		bugout(malloc_sym);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if ((lp->l_libname = strdup(name)) == NULL)
172*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
173*7c478bd9Sstevel@tonic-gate 	lp->l_handle = handle;
174*7c478bd9Sstevel@tonic-gate 	lp->l_next = NULL;
175*7c478bd9Sstevel@tonic-gate 	if (*listend)
176*7c478bd9Sstevel@tonic-gate 		(*listend)->l_next = lp;
177*7c478bd9Sstevel@tonic-gate 	if (*list == NULL)
178*7c478bd9Sstevel@tonic-gate 		*list = lp;
179*7c478bd9Sstevel@tonic-gate 	*listend = lp;
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Called abibasename() to avoid clash with basename(3C)
184*7c478bd9Sstevel@tonic-gate  * Incidentally, basename(3C) is destructive which is why
185*7c478bd9Sstevel@tonic-gate  * we are not using it instead.
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate char *
abibasename(const char * str)188*7c478bd9Sstevel@tonic-gate abibasename(const char *str)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	char *p;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	if ((p = strrchr(str, '/')) != NULL)
193*7c478bd9Sstevel@tonic-gate 		return (p + 1);
194*7c478bd9Sstevel@tonic-gate 	else
195*7c478bd9Sstevel@tonic-gate 		return ((char *)str);
196*7c478bd9Sstevel@tonic-gate }
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate Liblist *
check_list(Liblist * list,char const * str)199*7c478bd9Sstevel@tonic-gate check_list(Liblist *list, char const *str)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	char *basename1, *basename2, *p1, *p2;
202*7c478bd9Sstevel@tonic-gate 	Liblist *ret = NULL;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (list == NULL)
205*7c478bd9Sstevel@tonic-gate 		return (NULL);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 	if ((basename2 = strdup(abibasename(str))) == NULL)
208*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
209*7c478bd9Sstevel@tonic-gate 	if ((p2 = strchr(basename2, '.')) != NULL)
210*7c478bd9Sstevel@tonic-gate 		*p2 = '\0';
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	for (; list; list = list->l_next) {
213*7c478bd9Sstevel@tonic-gate 		/* Lose the dirname */
214*7c478bd9Sstevel@tonic-gate 		if ((basename1 = strdup(abibasename(list->l_libname))) == NULL)
215*7c478bd9Sstevel@tonic-gate 			bugout(strdup_sym);
216*7c478bd9Sstevel@tonic-gate 		/* Lose the suffix */
217*7c478bd9Sstevel@tonic-gate 		if ((p1 = strchr(basename1, '.')) != NULL)
218*7c478bd9Sstevel@tonic-gate 			*p1 = '\0';
219*7c478bd9Sstevel@tonic-gate 		if (fnmatch(basename1, basename2, 0) == 0) {
220*7c478bd9Sstevel@tonic-gate 			ret = list;
221*7c478bd9Sstevel@tonic-gate 			free(basename1);
222*7c478bd9Sstevel@tonic-gate 			break;
223*7c478bd9Sstevel@tonic-gate 		}
224*7c478bd9Sstevel@tonic-gate 		free(basename1);
225*7c478bd9Sstevel@tonic-gate 	}
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	free(basename2);
228*7c478bd9Sstevel@tonic-gate 	return (ret);
229*7c478bd9Sstevel@tonic-gate }
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate int
check_intlist(Intlist * list,char const * iface)232*7c478bd9Sstevel@tonic-gate check_intlist(Intlist *list, char const *iface)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	if (list == NULL)
235*7c478bd9Sstevel@tonic-gate 		return (0);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	for (; list != NULL; list = list->i_next) {
238*7c478bd9Sstevel@tonic-gate 		if (fnmatch(list->i_name, iface, 0) == 0)
239*7c478bd9Sstevel@tonic-gate 			return (1);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	return (0);
243*7c478bd9Sstevel@tonic-gate }
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate char *
checkenv(char const * env)246*7c478bd9Sstevel@tonic-gate checkenv(char const *env)
247*7c478bd9Sstevel@tonic-gate {
248*7c478bd9Sstevel@tonic-gate 	char *envstr;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 	if ((envstr = getenv(env)) == NULL)
251*7c478bd9Sstevel@tonic-gate 		return (NULL);
252*7c478bd9Sstevel@tonic-gate 	while (*envstr == ' ')
253*7c478bd9Sstevel@tonic-gate 		envstr++;
254*7c478bd9Sstevel@tonic-gate 	if (*envstr == '\0')
255*7c478bd9Sstevel@tonic-gate 		return (NULL);
256*7c478bd9Sstevel@tonic-gate 	return (envstr);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate int
build_interceptor_path(char * buf,size_t l,char const * path)260*7c478bd9Sstevel@tonic-gate build_interceptor_path(char *buf, size_t l, char const *path)
261*7c478bd9Sstevel@tonic-gate {
262*7c478bd9Sstevel@tonic-gate 	char *p, *t, *f;
263*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
264*7c478bd9Sstevel@tonic-gate 	char *m;
265*7c478bd9Sstevel@tonic-gate #endif
266*7c478bd9Sstevel@tonic-gate 	int ret;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	/* Duplicate the path */
269*7c478bd9Sstevel@tonic-gate 	if ((p = strdup(path)) == NULL)
270*7c478bd9Sstevel@tonic-gate 		bugout(strdup_sym);
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	/* Find the last slash, if there ain't one bug out */
273*7c478bd9Sstevel@tonic-gate 	if ((t = strrchr(p, '/')) == NULL) {
274*7c478bd9Sstevel@tonic-gate 		ret = 0;
275*7c478bd9Sstevel@tonic-gate 		goto done;
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/*
279*7c478bd9Sstevel@tonic-gate 	 * Wack the slash to a null byte.
280*7c478bd9Sstevel@tonic-gate 	 * Thus if we got:
281*7c478bd9Sstevel@tonic-gate 	 * 	/A/B/C/D.so.1
282*7c478bd9Sstevel@tonic-gate 	 * p now points to /A/B/C
283*7c478bd9Sstevel@tonic-gate 	 * f is set to point to D.so.1
284*7c478bd9Sstevel@tonic-gate 	 */
285*7c478bd9Sstevel@tonic-gate 	*t = '\0';
286*7c478bd9Sstevel@tonic-gate 	f = ++t;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate #if defined(_LP64)
289*7c478bd9Sstevel@tonic-gate 	/*
290*7c478bd9Sstevel@tonic-gate 	 * As above except that in LP64 (for sparc) we'll get:
291*7c478bd9Sstevel@tonic-gate 	 *	/A/B/C/sparcv9/D.so.1
292*7c478bd9Sstevel@tonic-gate 	 * thus p now points to:
293*7c478bd9Sstevel@tonic-gate 	 *	/A/B/C/sparcv9
294*7c478bd9Sstevel@tonic-gate 	 * so we repeat the wack so that we get:
295*7c478bd9Sstevel@tonic-gate 	 *	/A/B/C
296*7c478bd9Sstevel@tonic-gate 	 * and retain a pointer, m, to the machine dependent portion.
297*7c478bd9Sstevel@tonic-gate 	 */
298*7c478bd9Sstevel@tonic-gate 	if ((t = strrchr(p, '/')) == NULL) {
299*7c478bd9Sstevel@tonic-gate 		ret = 0;
300*7c478bd9Sstevel@tonic-gate 		goto done;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	*t = '\0';
303*7c478bd9Sstevel@tonic-gate 	m = ++t;
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	/*
306*7c478bd9Sstevel@tonic-gate 	 * Now we can build a path name.
307*7c478bd9Sstevel@tonic-gate 	 * This path is only a guess that'll be checked later in appendlist().
308*7c478bd9Sstevel@tonic-gate 	 * Some system libraries, like libc.so.1, reside in /lib while their
309*7c478bd9Sstevel@tonic-gate 	 * corresponding abi_* counterparts reside in /usr/lib.  The same is
310*7c478bd9Sstevel@tonic-gate 	 * true for libraries like libc_psr.so.1 that reside in /platform
311*7c478bd9Sstevel@tonic-gate 	 * rather than /usr/platform.  To deal with this, we check whether
312*7c478bd9Sstevel@tonic-gate 	 * the file in the direct path name we generate exists, and if not,
313*7c478bd9Sstevel@tonic-gate 	 * we prepend "/usr" to it.  This handles all existing cases.
314*7c478bd9Sstevel@tonic-gate 	 */
315*7c478bd9Sstevel@tonic-gate 	ret = snprintf(buf, l, "%s/abi/%s/abi_%s", p, m, f);
316*7c478bd9Sstevel@tonic-gate 	if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
317*7c478bd9Sstevel@tonic-gate 		ret = snprintf(buf, l, "/usr%s/abi/%s/abi_%s", p, m, f);
318*7c478bd9Sstevel@tonic-gate #else
319*7c478bd9Sstevel@tonic-gate 	ret = snprintf(buf, l, "%s/abi/abi_%s", p, f);
320*7c478bd9Sstevel@tonic-gate 	if (access(buf, R_OK) != 0 && strncmp(buf, "/usr/", 5) != 0)
321*7c478bd9Sstevel@tonic-gate 		ret = snprintf(buf, l, "/usr%s/abi/abi_%s", p, f);
322*7c478bd9Sstevel@tonic-gate #endif
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate done:
325*7c478bd9Sstevel@tonic-gate 	free(p);
326*7c478bd9Sstevel@tonic-gate 	return (ret);
327*7c478bd9Sstevel@tonic-gate }
328