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