ldlibs.c revision 4734:a4708faa3e85
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 2007 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 */
48static 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 */
57static char *
58compat_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
86static char *
87process_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) ==
101					    0)
102						return ((char *)S_ERROR);
103			} else
104				if (list_appendc(list, subsflag ?
105				    compat_YL_YU(ofl, path, i) : path) == 0)
106					return ((char *)S_ERROR);
107			return (cp);
108		}
109
110		if (*cp == ':') {
111			*cp = '\0';
112			if (cp == path) {
113				if (list_appendc(list, subsflag ?
114				    compat_YL_YU(ofl, dot, i) : dot) == 0)
115					return ((char *)S_ERROR);
116			} else {
117				if (list_appendc(list, subsflag ?
118				    compat_YL_YU(ofl, path, i) : path) == 0)
119					return ((char *)S_ERROR);
120			}
121			path = cp + 1;
122			seenflg = TRUE;
123			continue;
124		}
125
126		/* case ";" */
127
128		if (cp != path) {
129			if (list_appendc(list, subsflag ?
130			    compat_YL_YU(ofl, path, i) : path) == 0)
131				return ((char *)S_ERROR);
132		} else {
133			if (seenflg)
134				if (list_appendc(list, subsflag ?
135				    compat_YL_YU(ofl, dot, i) : dot) == 0)
136					return ((char *)S_ERROR);
137		}
138		return (cp);
139	}
140	/* NOTREACHED */
141	return (NULL);	/* keep gcc happy */
142}
143
144/*
145 * adds the indicated path to those to be searched for libraries.
146 */
147uintptr_t
148ld_add_libdir(Ofl_desc *ofl, const char *path)
149{
150	if (insert_lib == NULL) {
151		if (list_prependc(&ofl->ofl_ulibdirs, path) == 0)
152			return (S_ERROR);
153		insert_lib = ofl->ofl_ulibdirs.head;
154	} else
155		if ((insert_lib = list_insertc(&ofl->ofl_ulibdirs, path,
156		    insert_lib)) == 0)
157			return (S_ERROR);
158
159	/*
160	 * As -l and -L options can be interspersed, print the library
161	 * search paths each time a new path is added.
162	 */
163	DBG_CALL(Dbg_libs_update(ofl->ofl_lml, &ofl->ofl_ulibdirs,
164	    &ofl->ofl_dlibdirs));
165	return (1);
166}
167
168/*
169 * Process a required library.  Combine the directory and filename, and then
170 * append either a `.so' or `.a' suffix and try opening the associated pathname.
171 */
172static Ifl_desc *
173find_lib_name(const char *dir, const char *file, Ofl_desc *ofl, Rej_desc *rej)
174{
175	int		fd;
176	size_t		dlen;
177	char		*_path, path[PATH_MAX + 2];
178	const char	*_dir = dir;
179	Ifl_desc	*ifl;
180
181	/*
182	 * Determine the size of the directory.  The directory and filename are
183	 * concatenated into the local buffer which is purposely larger than
184	 * PATH_MAX.  Should a pathname be created that exceeds the system
185	 * limit, the open() will catch it, and a suitable rejection message is
186	 * saved.
187	 */
188	if ((dlen = strlen(dir)) == 0) {
189		_dir = (char *)MSG_ORIG(MSG_STR_DOT);
190		dlen = 1;
191	}
192	dlen++;
193
194	/*
195	 * If we are in dynamic mode try and open the associated shared object.
196	 */
197	if (ofl->ofl_flags & FLG_OF_DYNLIBS) {
198		(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_SO),
199		    _dir, file);
200		DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
201		if ((fd = open(path, O_RDONLY)) != -1) {
202
203			if ((_path = libld_malloc(strlen(path) + 1)) == 0)
204				return ((Ifl_desc *)S_ERROR);
205			(void) strcpy(_path, path);
206
207			ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
208			    FLG_IF_NEEDED, rej);
209			if (fd != -1)
210				(void) close(fd);
211			return (ifl);
212
213		} else if (errno != ENOENT) {
214			/*
215			 * If the open() failed for anything other than the
216			 * file not existing, record the error condition.
217			 */
218			rej->rej_type = SGS_REJ_STR;
219			rej->rej_str = strerror(errno);
220			rej->rej_name = strdup(path);
221		}
222	}
223
224	/*
225	 * If we are not in dynamic mode, or a shared object could not be
226	 * located, try and open the associated archive.
227	 */
228	(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_A),
229	    _dir, file);
230	DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
231	if ((fd = open(path, O_RDONLY)) != -1) {
232
233		if ((_path = libld_malloc(strlen(path) + 1)) == 0)
234			return ((Ifl_desc *)S_ERROR);
235		(void) strcpy(_path, path);
236
237		ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
238		    FLG_IF_NEEDED, rej);
239		if (fd != -1)
240			(void) close(fd);
241		return (ifl);
242
243	} else if (errno != ENOENT) {
244		/*
245		 * If the open() failed for anything other than the
246		 * file not existing, record the error condition.
247		 */
248		rej->rej_type = SGS_REJ_STR;
249		rej->rej_str = strerror(errno);
250		rej->rej_name = strdup(path);
251	}
252
253	return (0);
254}
255
256/*
257 * Take the abbreviated name of a library file (from -lfoo) and searches for the
258 * library.  The search path rules are:
259 *
260 *	o	use any user supplied paths, i.e. LD_LIBRARY_PATH and -L, then
261 *
262 *	o	use the default directories, i.e. LIBPATH or -YP.
263 *
264 * If we are in dynamic mode and -Bstatic is not in effect, first look for a
265 * shared object with full name: path/libfoo.so; then [or else] look for an
266 * archive with name: path/libfoo.a.  If no file is found, it's a fatal error,
267 * otherwise process the file appropriately depending on its type.
268 */
269uintptr_t
270ld_find_library(const char *name, Ofl_desc *ofl)
271{
272	Listnode	*lnp;
273	char		*path;
274	Ifl_desc	*ifl = 0;
275	Rej_desc	rej = { 0 };
276
277	/*
278	 * Search for this file in any user defined directories.
279	 */
280	for (LIST_TRAVERSE(&ofl->ofl_ulibdirs, lnp, path)) {
281		Rej_desc	_rej = { 0 };
282
283		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
284			if (_rej.rej_type && (rej.rej_type == 0))
285				rej = _rej;
286			continue;
287		}
288		return ((uintptr_t)ifl);
289	}
290
291	/*
292	 * Finally try the default library search directories.
293	 */
294	for (LIST_TRAVERSE(&ofl->ofl_dlibdirs, lnp, path)) {
295		Rej_desc	_rej = { 0 };
296
297		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
298			if (_rej.rej_type && (rej.rej_type == 0))
299				rej = _rej;
300			continue;
301		}
302		return ((uintptr_t)ifl);
303	}
304
305	/*
306	 * If we've got this far we haven't found a shared object or archive.
307	 * If an object was found, but was rejected for some reason, print a
308	 * diagnostic to that effect, otherwise generate a generic "not found"
309	 * diagnostic.
310	 */
311	if (rej.rej_type) {
312		Conv_reject_desc_buf_t rej_buf;
313
314		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
315		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
316		    conv_reject_desc(&rej, &rej_buf));
317	} else {
318		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND),
319		    name);
320	}
321
322	ofl->ofl_flags |= FLG_OF_FATAL;
323	return (0);
324}
325
326/*
327 * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
328 * specified), and set up the directory list from which to search for
329 * libraries.  From the man page:
330 *
331 *	LD_LIBRARY_PATH=dirlist1;dirlist2
332 * and
333 *	ld ... -Lpath1 ... -Lpathn ...
334 *
335 * results in a search order of:
336 *
337 *	dirlist1 path1 ... pathn dirlist2 LIBPATH
338 *
339 * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
340 * all taken as dirlist2.
341 */
342uintptr_t
343ld_lib_setup(Ofl_desc * ofl)
344{
345	char	*path, *cp = NULL;
346
347	/*
348	 * Determine whether an LD_LIBRARY_PATH setting is in effect.
349	 */
350	if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
351#if	defined(_ELF64)
352		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
353#else
354		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
355#endif
356			cp  = getenv(MSG_ORIG(MSG_LD_LIBPATH));
357	}
358
359	if ((cp != NULL) && (*cp != '\0')) {
360		if ((path = libld_malloc(strlen(cp) + 1)) == 0)
361			return (S_ERROR);
362		(void) strcpy(path, cp);
363		DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
364
365		/*
366		 * Process the first path string (anything up to a null or
367		 * a `;');
368		 */
369		path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
370
371
372		/*
373		 * If a `;' was seen then initialize the insert flag to the
374		 * tail of this list.  This is where any -L paths will be
375		 * added (otherwise -L paths are prepended to this list).
376		 * Continue to process the remaining path string.
377		 */
378		if (path) {
379			insert_lib = ofl->ofl_ulibdirs.tail;
380			*path = '\0';
381			++path;
382			cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
383			    FALSE);
384			if (cp == (char *)S_ERROR)
385				return (S_ERROR);
386			else if (cp)
387				eprintf(ofl->ofl_lml, ERR_WARNING,
388				    MSG_INTL(MSG_LIB_MALFORM));
389		}
390	}
391
392	/*
393	 * Add the default LIBPATH or any -YP supplied path.
394	 */
395	DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
396	cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
397	if (cp == (char *)S_ERROR)
398		return (S_ERROR);
399	else if (cp) {
400		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
401		return (S_ERROR);
402	}
403	DBG_CALL(Dbg_libs_init(ofl->ofl_lml, &ofl->ofl_ulibdirs,
404	    &ofl->ofl_dlibdirs));
405	return (1);
406}
407