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