xref: /illumos-gate/usr/src/cmd/sgs/libld/common/ldlibs.c (revision 168c213023b7f347f11abfc72f448b0c621ab718)
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 			if (fd != -1)
209 				(void) close(fd);
210 			return (ifl);
211 
212 		} else if (errno != ENOENT) {
213 			/*
214 			 * If the open() failed for anything other than the
215 			 * file not existing, record the error condition.
216 			 */
217 			rej->rej_type = SGS_REJ_STR;
218 			rej->rej_str = strerror(errno);
219 			rej->rej_name = strdup(path);
220 		}
221 	}
222 
223 	/*
224 	 * If we are not in dynamic mode, or a shared object could not be
225 	 * located, try and open the associated archive.
226 	 */
227 	(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_A),
228 	    _dir, file);
229 	DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
230 	if ((fd = open(path, O_RDONLY)) != -1) {
231 
232 		if ((_path = libld_malloc(strlen(path) + 1)) == 0)
233 			return ((Ifl_desc *)S_ERROR);
234 		(void) strcpy(_path, path);
235 
236 		ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
237 		    FLG_IF_NEEDED, rej);
238 		if (fd != -1)
239 			(void) close(fd);
240 		return (ifl);
241 
242 	} else if (errno != ENOENT) {
243 		/*
244 		 * If the open() failed for anything other than the
245 		 * file not existing, record the error condition.
246 		 */
247 		rej->rej_type = SGS_REJ_STR;
248 		rej->rej_str = strerror(errno);
249 		rej->rej_name = strdup(path);
250 	}
251 
252 	return (0);
253 }
254 
255 /*
256  * Take the abbreviated name of a library file (from -lfoo) and searches for the
257  * library.  The search path rules are:
258  *
259  *	o	use any user supplied paths, i.e. LD_LIBRARY_PATH and -L, then
260  *
261  *	o	use the default directories, i.e. LIBPATH or -YP.
262  *
263  * If we are in dynamic mode and -Bstatic is not in effect, first look for a
264  * shared object with full name: path/libfoo.so; then [or else] look for an
265  * archive with name: path/libfoo.a.  If no file is found, it's a fatal error,
266  * otherwise process the file appropriately depending on its type.
267  */
268 uintptr_t
269 ld_find_library(const char *name, Ofl_desc *ofl)
270 {
271 	Listnode	*lnp;
272 	char		*path;
273 	Ifl_desc	*ifl = 0;
274 	Rej_desc	rej = { 0 };
275 
276 	/*
277 	 * Search for this file in any user defined directories.
278 	 */
279 	for (LIST_TRAVERSE(&ofl->ofl_ulibdirs, lnp, path)) {
280 		Rej_desc	_rej = { 0 };
281 
282 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
283 			if (_rej.rej_type && (rej.rej_type == 0))
284 				rej = _rej;
285 			continue;
286 		}
287 		return ((uintptr_t)ifl);
288 	}
289 
290 	/*
291 	 * Finally try the default library search directories.
292 	 */
293 	for (LIST_TRAVERSE(&ofl->ofl_dlibdirs, lnp, path)) {
294 		Rej_desc	_rej = { 0 };
295 
296 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == 0) {
297 			if (_rej.rej_type && (rej.rej_type == 0))
298 				rej = _rej;
299 			continue;
300 		}
301 		return ((uintptr_t)ifl);
302 	}
303 
304 	/*
305 	 * If we've got this far we haven't found a shared object or archive.
306 	 * If an object was found, but was rejected for some reason, print a
307 	 * diagnostic to that effect, otherwise generate a generic "not found"
308 	 * diagnostic.
309 	 */
310 	if (rej.rej_type)
311 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
312 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
313 		    conv_reject_desc(&rej));
314 	else
315 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND),
316 		    name);
317 
318 	ofl->ofl_flags |= FLG_OF_FATAL;
319 	return (0);
320 }
321 
322 /*
323  * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
324  * specified), and set up the directory list from which to search for
325  * libraries.  From the man page:
326  *
327  *	LD_LIBRARY_PATH=dirlist1;dirlist2
328  * and
329  *	ld ... -Lpath1 ... -Lpathn ...
330  *
331  * results in a search order of:
332  *
333  *	dirlist1 path1 ... pathn dirlist2 LIBPATH
334  *
335  * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
336  * all taken as dirlist2.
337  */
338 uintptr_t
339 ld_lib_setup(Ofl_desc * ofl)
340 {
341 	char	*path, *cp = NULL;
342 
343 	/*
344 	 * Determine whether an LD_LIBRARY_PATH setting is in effect.
345 	 */
346 	if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
347 #if	defined(_ELF64)
348 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
349 #else
350 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
351 #endif
352 		    cp  = getenv(MSG_ORIG(MSG_LD_LIBPATH));
353 	}
354 
355 	if ((cp != NULL) && (*cp != '\0')) {
356 		if ((path = libld_malloc(strlen(cp) + 1)) == 0)
357 			return (S_ERROR);
358 		(void) strcpy(path, cp);
359 		DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
360 
361 		/*
362 		 * Process the first path string (anything up to a null or
363 		 * a `;');
364 		 */
365 		path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
366 
367 
368 		/*
369 		 * If a `;' was seen then initialize the insert flag to the
370 		 * tail of this list.  This is where any -L paths will be
371 		 * added (otherwise -L paths are prepended to this list).
372 		 * Continue to process the remaining path string.
373 		 */
374 		if (path) {
375 			insert_lib = ofl->ofl_ulibdirs.tail;
376 			*path = '\0';
377 			++path;
378 			cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
379 			    FALSE);
380 			if (cp == (char *)S_ERROR)
381 				return (S_ERROR);
382 			else if (cp)
383 				eprintf(ofl->ofl_lml, ERR_WARNING,
384 				    MSG_INTL(MSG_LIB_MALFORM));
385 		}
386 	}
387 
388 	/*
389 	 * Add the default LIBPATH or any -YP supplied path.
390 	 */
391 	DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
392 	cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
393 	if (cp == (char *)S_ERROR)
394 		return (S_ERROR);
395 	else if (cp) {
396 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
397 		return (S_ERROR);
398 	}
399 	DBG_CALL(Dbg_libs_init(ofl->ofl_lml, &ofl->ofl_ulibdirs,
400 	    &ofl->ofl_dlibdirs));
401 	return (1);
402 }
403