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