xref: /illumos-gate/usr/src/cmd/sgs/libld/common/ldlibs.c (revision 85bb5f1d)
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 2008 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) ==
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  */
147 uintptr_t
148 ld_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  */
172 static Ifl_desc *
173 find_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  */
269 uintptr_t
270 ld_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, ld_targ.t_m.m_mach));
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  */
342 uintptr_t
343 ld_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