xref: /titanic_52/usr/src/cmd/sgs/libld/common/ldlibs.c (revision 18c2aff776a775d34a4c9893a4c72e0434d68e36)
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 /*
23  *	Copyright (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*
33  * Library processing
34  */
35 #include	<stdio.h>
36 #include	<unistd.h>
37 #include	<fcntl.h>
38 #include	<string.h>
39 #include	<limits.h>
40 #include	<errno.h>
41 #include	<debug.h>
42 #include	"msg.h"
43 #include	"_libld.h"
44 
45 /*
46  * List of support libraries specified (-S option).
47  */
48 static Listnode *	insert_lib;
49 
50 /*
51  * Function to handle -YL and -YU substitutions in LIBPATH.  It's probably
52  * very unlikely that the link-editor will ever see this, as any use of these
53  * options is normally processed by the compiler driver first and the finished
54  * -YP string is sent to us.  The fact that these two options are not even
55  * documented anymore makes it even more unlikely this processing will occur.
56  */
57 static char *
58 compat_YL_YU(Ofl_desc *ofl, char *path, int index)
59 {
60 	if (index == YLDIR) {
61 		if (Llibdir) {
62 			/*
63 			 * User supplied "-YL,libdir", this is the pathname that
64 			 * corresponds for compatibility to -YL (as defined in
65 			 * sgs/include/paths.h)
66 			 */
67 			DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Llibdir,
68 			    path, index));
69 			return (Llibdir);
70 		}
71 	} else if (index == YUDIR) {
72 		if (Ulibdir) {
73 			/*
74 			 * User supplied "-YU,libdir", this is the pathname that
75 			 * corresponds for compatibility to -YU (as defined in
76 			 * sgs/include/paths.h)
77 			 */
78 			DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Ulibdir,
79 			    path, index));
80 			return (Ulibdir);
81 		}
82 	}
83 	return (path);
84 }
85 
86 static char *
87 process_lib_path(Ofl_desc *ofl, List *list, char *path, Boolean subsflag)
88 {
89 	int	i;
90 	char	*cp;
91 	Boolean	seenflg = FALSE;
92 	char	*dot = (char *)MSG_ORIG(MSG_STR_DOT);
93 
94 	for (i = YLDIR; i; i++) {
95 		cp = strpbrk(path, MSG_ORIG(MSG_STR_PATHTOK));
96 		if (cp == NULL) {
97 			if (*path == '\0') {
98 				if (seenflg)
99 				    if (list_appendc(list, subsflag ?
100 					compat_YL_YU(ofl, dot, i) : dot) == 0)
101 					    return ((char *)S_ERROR);
102 			} else
103 				if (list_appendc(list, subsflag ?
104 				    compat_YL_YU(ofl, path, i) : path) == 0)
105 					return ((char *)S_ERROR);
106 			return (cp);
107 		}
108 
109 		if (*cp == ':') {
110 			*cp = '\0';
111 			if (cp == path) {
112 				if (list_appendc(list, subsflag ?
113 				    compat_YL_YU(ofl, dot, i) : dot) == 0)
114 					return ((char *)S_ERROR);
115 			} else {
116 				if (list_appendc(list, subsflag ?
117 				    compat_YL_YU(ofl, path, i) : path) == 0)
118 					return ((char *)S_ERROR);
119 			}
120 			path = cp + 1;
121 			seenflg = TRUE;
122 			continue;
123 		}
124 
125 		/* case ";" */
126 
127 		if (cp != path) {
128 			if (list_appendc(list, subsflag ?
129 			    compat_YL_YU(ofl, path, i) : path) == 0)
130 				return ((char *)S_ERROR);
131 		} else {
132 			if (seenflg)
133 				if (list_appendc(list, subsflag ?
134 				    compat_YL_YU(ofl, dot, i) : dot) == 0)
135 					return ((char *)S_ERROR);
136 		}
137 		return (cp);
138 	}
139 	/* NOTREACHED */
140 	return (NULL);	/* keep gcc happy */
141 }
142 
143 /*
144  * adds the indicated path to those to be searched for libraries.
145  */
146 uintptr_t
147 ld_add_libdir(Ofl_desc *ofl, const char *path)
148 {
149 	if (insert_lib == NULL) {
150 		if (list_prependc(&ofl->ofl_ulibdirs, path) == 0)
151 			return (S_ERROR);
152 		insert_lib = ofl->ofl_ulibdirs.head;
153 	} else
154 		if ((insert_lib = list_insertc(&ofl->ofl_ulibdirs, path,
155 		    insert_lib)) == 0)
156 			return (S_ERROR);
157 
158 	/*
159 	 * As -l and -L options can be interspersed, print the library
160 	 * search paths each time a new path is added.
161 	 */
162 	DBG_CALL(Dbg_libs_update(ofl->ofl_lml, &ofl->ofl_ulibdirs,
163 	    &ofl->ofl_dlibdirs));
164 	return (1);
165 }
166 
167 /*
168  * Process a required library.  Combine the directory and filename, and then
169  * append either a `.so' or `.a' suffix and try opening the associated pathname.
170  */
171 static Ifl_desc *
172 find_lib_name(const char *dir, const char *file, Ofl_desc *ofl, Rej_desc *rej)
173 {
174 	int		fd;
175 	size_t		dlen;
176 	char		*_path, path[PATH_MAX + 2];
177 	const char	*_dir = dir;
178 	Ifl_desc	*ifl;
179 
180 	/*
181 	 * Determine the size of the directory.  The directory and filename are
182 	 * concatenated into the local buffer which is purposely larger than
183 	 * PATH_MAX.  Should a pathname be created that exceeds the system
184 	 * limit, the open() will catch it, and a suitable rejection message is
185 	 * saved.
186 	 */
187 	if ((dlen = strlen(dir)) == 0) {
188 		_dir = (char *)MSG_ORIG(MSG_STR_DOT);
189 		dlen = 1;
190 	}
191 	dlen++;
192 
193 	/*
194 	 * If we are in dynamic mode try and open the associated shared object.
195 	 */
196 	if (ofl->ofl_flags & FLG_OF_DYNLIBS) {
197 		(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_SO),
198 		    _dir, file);
199 		DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
200 		if ((fd = open(path, O_RDONLY)) != -1) {
201 
202 			if ((_path = libld_malloc(strlen(path) + 1)) == 0)
203 				return ((Ifl_desc *)S_ERROR);
204 			(void) strcpy(_path, path);
205 
206 			ifl = ld_process_open(_path, &_path[dlen], fd, ofl,
207 			    FLG_IF_NEEDED, rej);
208 			(void) close(fd);
209 			return (ifl);
210 
211 		} else if (errno != ENOENT) {
212 			/*
213 			 * If the open() failed for anything other than the
214 			 * file not existing, record the error condition.
215 			 */
216 			rej->rej_type = SGS_REJ_STR;
217 			rej->rej_str = strerror(errno);
218 			rej->rej_name = strdup(path);
219 		}
220 	}
221 
222 	/*
223 	 * If we are not in dynamic mode, or a shared object could not be
224 	 * located, try and open the associated archive.
225 	 */
226 	(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_A),
227 	    _dir, file);
228 	DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
229 	if ((fd = open(path, O_RDONLY)) != -1) {
230 
231 		if ((_path = libld_malloc(strlen(path) + 1)) == 0)
232 			return ((Ifl_desc *)S_ERROR);
233 		(void) strcpy(_path, path);
234 
235 		ifl = ld_process_open(_path, &_path[dlen], fd, ofl,
236 		    FLG_IF_NEEDED, rej);
237 		(void) close(fd);
238 		return (ifl);
239 
240 	} else if (errno != ENOENT) {
241 		/*
242 		 * If the open() failed for anything other than the
243 		 * file not existing, record the error condition.
244 		 */
245 		rej->rej_type = SGS_REJ_STR;
246 		rej->rej_str = strerror(errno);
247 		rej->rej_name = strdup(path);
248 	}
249 
250 	return (0);
251 }
252 
253 /*
254  * Take the abbreviated name of a library file (from -lfoo) and searches for the
255  * library.  The search path rules are:
256  *
257  *	o	use any user supplied paths, i.e. LD_LIBRARY_PATH and -L, then
258  *
259  *	o	use the default directories, i.e. LIBPATH or -YP.
260  *
261  * If we are in dynamic mode and -Bstatic is not in effect, first look for a
262  * shared object with full name: path/libfoo.so; then [or else] look for an
263  * archive with name: path/libfoo.a.  If no file is found, it's a fatal error,
264  * otherwise process the file appropriately depending on its type.
265  */
266 uintptr_t
267 ld_find_library(const char *name, Ofl_desc *ofl)
268 {
269 	Listnode	*lnp;
270 	char		*path;
271 	Ifl_desc	*ifl = 0;
272 	Rej_desc	rej = { 0 };
273 
274 	/*
275 	 * Search for this file in any user defined directories.
276 	 */
277 	for (LIST_TRAVERSE(&ofl->ofl_ulibdirs, lnp, path)) {
278 		Rej_desc	_rej = { 0 };
279 
280 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
281 			if (_rej.rej_type && (rej.rej_type == 0))
282 				rej = _rej;
283 			continue;
284 		}
285 		return ((uintptr_t)ifl);
286 	}
287 
288 	/*
289 	 * Finally try the default library search directories.
290 	 */
291 	for (LIST_TRAVERSE(&ofl->ofl_dlibdirs, lnp, path)) {
292 		Rej_desc	_rej = { 0 };
293 
294 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
295 			if (_rej.rej_type && (rej.rej_type == 0))
296 				rej = _rej;
297 			continue;
298 		}
299 		return ((uintptr_t)ifl);
300 	}
301 
302 	/*
303 	 * If we've got this far we haven't found a shared object or archive.
304 	 * If an object was found, but was rejected for some reason, print a
305 	 * diagnostic to that effect, otherwise generate a generic "not found"
306 	 * diagnostic.
307 	 */
308 	if (rej.rej_type)
309 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
310 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
311 		    conv_reject_desc(&rej));
312 	else
313 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND),
314 		    name);
315 
316 	ofl->ofl_flags |= FLG_OF_FATAL;
317 	return (0);
318 }
319 
320 /*
321  * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
322  * specified), and set up the directory list from which to search for
323  * libraries.  From the man page:
324  *
325  *	LD_LIBRARY_PATH=dirlist1;dirlist2
326  * and
327  *	ld ... -Lpath1 ... -Lpathn ...
328  *
329  * results in a search order of:
330  *
331  *	dirlist1 path1 ... pathn dirlist2 LIBPATH
332  *
333  * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
334  * all taken as dirlist2.
335  */
336 uintptr_t
337 ld_lib_setup(Ofl_desc * ofl)
338 {
339 	char	*path, *cp = NULL;
340 
341 	/*
342 	 * Determine whether an LD_LIBRARY_PATH setting is in effect.
343 	 */
344 	if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
345 #if	defined(_ELF64)
346 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
347 #else
348 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
349 #endif
350 		    cp  = getenv(MSG_ORIG(MSG_LD_LIBPATH));
351 	}
352 
353 	if ((cp != NULL) && (*cp != '\0')) {
354 		if ((path = libld_malloc(strlen(cp) + 1)) == 0)
355 			return (S_ERROR);
356 		(void) strcpy(path, cp);
357 		DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
358 
359 		/*
360 		 * Process the first path string (anything up to a null or
361 		 * a `;');
362 		 */
363 		path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
364 
365 
366 		/*
367 		 * If a `;' was seen then initialize the insert flag to the
368 		 * tail of this list.  This is where any -L paths will be
369 		 * added (otherwise -L paths are prepended to this list).
370 		 * Continue to process the remaining path string.
371 		 */
372 		if (path) {
373 			insert_lib = ofl->ofl_ulibdirs.tail;
374 			*path = '\0';
375 			++path;
376 			cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
377 			    FALSE);
378 			if (cp == (char *)S_ERROR)
379 				return (S_ERROR);
380 			else if (cp)
381 				eprintf(ofl->ofl_lml, ERR_WARNING,
382 				    MSG_INTL(MSG_LIB_MALFORM));
383 		}
384 	}
385 
386 	/*
387 	 * Add the default LIBPATH or any -YP supplied path.
388 	 */
389 	DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
390 	cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
391 	if (cp == (char *)S_ERROR)
392 		return (S_ERROR);
393 	else if (cp) {
394 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
395 		return (S_ERROR);
396 	}
397 	DBG_CALL(Dbg_libs_init(ofl->ofl_lml, &ofl->ofl_ulibdirs,
398 	    &ofl->ofl_dlibdirs));
399 	return (1);
400 }
401