xref: /illumos-gate/usr/src/cmd/sgs/libld/common/ldlibs.c (revision 57c40785)
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 /*
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  * List of support libraries specified (-S option).
45  */
46 static Listnode	*insert_lib;
47 
48 /*
49  * Function to handle -YL and -YU substitutions in LIBPATH.  It's probably
50  * very unlikely that the link-editor will ever see this, as any use of these
51  * options is normally processed by the compiler driver first and the finished
52  * -YP string is sent to us.  The fact that these two options are not even
53  * documented anymore makes it even more unlikely this processing will occur.
54  */
55 static char *
56 compat_YL_YU(Ofl_desc *ofl, char *path, int index)
57 {
58 	if (index == YLDIR) {
59 		if (Llibdir) {
60 			/*
61 			 * User supplied "-YL,libdir", this is the pathname that
62 			 * corresponds for compatibility to -YL (as defined in
63 			 * sgs/include/paths.h)
64 			 */
65 			DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Llibdir,
66 			    path, index));
67 			return (Llibdir);
68 		}
69 	} else if (index == YUDIR) {
70 		if (Ulibdir) {
71 			/*
72 			 * User supplied "-YU,libdir", this is the pathname that
73 			 * corresponds for compatibility to -YU (as defined in
74 			 * sgs/include/paths.h)
75 			 */
76 			DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Ulibdir,
77 			    path, index));
78 			return (Ulibdir);
79 		}
80 	}
81 	return (path);
82 }
83 
84 static char *
85 process_lib_path(Ofl_desc *ofl, List *list, char *path, Boolean subsflag)
86 {
87 	int	i;
88 	char	*cp;
89 	Boolean	seenflg = FALSE;
90 	char	*dot = (char *)MSG_ORIG(MSG_STR_DOT);
91 
92 	for (i = YLDIR; i; i++) {
93 		cp = strpbrk(path, MSG_ORIG(MSG_STR_PATHTOK));
94 		if (cp == NULL) {
95 			if (*path == '\0') {
96 				if (seenflg)
97 					if (list_appendc(list, subsflag ?
98 					    compat_YL_YU(ofl, dot, i) : dot) ==
99 					    0)
100 						return ((char *)S_ERROR);
101 			} else
102 				if (list_appendc(list, subsflag ?
103 				    compat_YL_YU(ofl, 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(ofl, dot, i) : dot) == 0)
113 					return ((char *)S_ERROR);
114 			} else {
115 				if (list_appendc(list, subsflag ?
116 				    compat_YL_YU(ofl, 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(ofl, path, i) : path) == 0)
129 				return ((char *)S_ERROR);
130 		} else {
131 			if (seenflg)
132 				if (list_appendc(list, subsflag ?
133 				    compat_YL_YU(ofl, 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 ld_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_lml, &ofl->ofl_ulibdirs,
162 	    &ofl->ofl_dlibdirs));
163 	return (1);
164 }
165 
166 /*
167  * Process a required library.  Combine the directory and filename, and then
168  * append either a `.so' or `.a' suffix and try opening the associated pathname.
169  */
170 static Ifl_desc *
171 find_lib_name(const char *dir, const char *file, Ofl_desc *ofl, Rej_desc *rej)
172 {
173 	int		fd;
174 	size_t		dlen;
175 	char		*_path, path[PATH_MAX + 2];
176 	const char	*_dir = dir;
177 	Ifl_desc	*ifl;
178 
179 	/*
180 	 * Determine the size of the directory.  The directory and filename are
181 	 * concatenated into the local buffer which is purposely larger than
182 	 * PATH_MAX.  Should a pathname be created that exceeds the system
183 	 * limit, the open() will catch it, and a suitable rejection message is
184 	 * saved.
185 	 */
186 	if ((dlen = strlen(dir)) == 0) {
187 		_dir = (char *)MSG_ORIG(MSG_STR_DOT);
188 		dlen = 1;
189 	}
190 	dlen++;
191 
192 	/*
193 	 * If we are in dynamic mode try and open the associated shared object.
194 	 */
195 	if (ofl->ofl_flags & FLG_OF_DYNLIBS) {
196 		(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_SO),
197 		    _dir, file);
198 		DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
199 		if ((fd = open(path, O_RDONLY)) != -1) {
200 
201 			if ((_path = libld_malloc(strlen(path) + 1)) == 0)
202 				return ((Ifl_desc *)S_ERROR);
203 			(void) strcpy(_path, path);
204 
205 			ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
206 			    FLG_IF_NEEDED, rej);
207 			if (fd != -1)
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, &_path[dlen], &fd, ofl,
236 		    FLG_IF_NEEDED, rej);
237 		if (fd != -1)
238 			(void) close(fd);
239 		return (ifl);
240 
241 	} else if (errno != ENOENT) {
242 		/*
243 		 * If the open() failed for anything other than the
244 		 * file not existing, record the error condition.
245 		 */
246 		rej->rej_type = SGS_REJ_STR;
247 		rej->rej_str = strerror(errno);
248 		rej->rej_name = strdup(path);
249 	}
250 
251 	return (NULL);
252 }
253 
254 /*
255  * Take the abbreviated name of a library file (from -lfoo) and searches for the
256  * library.  The search path rules are:
257  *
258  *	o	use any user supplied paths, i.e. LD_LIBRARY_PATH and -L, then
259  *
260  *	o	use the default directories, i.e. LIBPATH or -YP.
261  *
262  * If we are in dynamic mode and -Bstatic is not in effect, first look for a
263  * shared object with full name: path/libfoo.so; then [or else] look for an
264  * archive with name: path/libfoo.a.  If no file is found, it's a fatal error,
265  * otherwise process the file appropriately depending on its type.
266  */
267 uintptr_t
268 ld_find_library(const char *name, Ofl_desc *ofl)
269 {
270 	Listnode	*lnp;
271 	char		*path;
272 	Ifl_desc	*ifl = 0;
273 	Rej_desc	rej = { 0 };
274 
275 	/*
276 	 * Search for this file in any user defined directories.
277 	 */
278 	for (LIST_TRAVERSE(&ofl->ofl_ulibdirs, lnp, path)) {
279 		Rej_desc	_rej = { 0 };
280 
281 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == NULL) {
282 			if (_rej.rej_type && (rej.rej_type == 0))
283 				rej = _rej;
284 			continue;
285 		}
286 		return ((uintptr_t)ifl);
287 	}
288 
289 	/*
290 	 * Finally try the default library search directories.
291 	 */
292 	for (LIST_TRAVERSE(&ofl->ofl_dlibdirs, lnp, path)) {
293 		Rej_desc	_rej = { 0 };
294 
295 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == NULL) {
296 			if (_rej.rej_type && (rej.rej_type == 0))
297 				rej = _rej;
298 			continue;
299 		}
300 		return ((uintptr_t)ifl);
301 	}
302 
303 	/*
304 	 * If we've got this far we haven't found a shared object or archive.
305 	 * If an object was found, but was rejected for some reason, print a
306 	 * diagnostic to that effect, otherwise generate a generic "not found"
307 	 * diagnostic.
308 	 */
309 	if (rej.rej_type) {
310 		Conv_reject_desc_buf_t rej_buf;
311 
312 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
313 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
314 		    conv_reject_desc(&rej, &rej_buf, ld_targ.t_m.m_mach));
315 	} else {
316 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND),
317 		    name);
318 	}
319 
320 	ofl->ofl_flags |= FLG_OF_FATAL;
321 	return (0);
322 }
323 
324 /*
325  * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
326  * specified), and set up the directory list from which to search for
327  * libraries.  From the man page:
328  *
329  *	LD_LIBRARY_PATH=dirlist1;dirlist2
330  * and
331  *	ld ... -Lpath1 ... -Lpathn ...
332  *
333  * results in a search order of:
334  *
335  *	dirlist1 path1 ... pathn dirlist2 LIBPATH
336  *
337  * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
338  * all taken as dirlist2.
339  */
340 uintptr_t
341 ld_lib_setup(Ofl_desc *ofl)
342 {
343 	char	*path, *cp = NULL;
344 
345 	/*
346 	 * Determine whether an LD_LIBRARY_PATH setting is in effect.
347 	 */
348 	if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
349 #if	defined(_ELF64)
350 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
351 #else
352 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
353 #endif
354 			cp  = getenv(MSG_ORIG(MSG_LD_LIBPATH));
355 	}
356 
357 	if ((cp != NULL) && (*cp != '\0')) {
358 		if ((path = libld_malloc(strlen(cp) + 1)) == 0)
359 			return (S_ERROR);
360 		(void) strcpy(path, cp);
361 		DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
362 
363 		/*
364 		 * Process the first path string (anything up to a null or
365 		 * a `;');
366 		 */
367 		path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
368 
369 
370 		/*
371 		 * If a `;' was seen then initialize the insert flag to the
372 		 * tail of this list.  This is where any -L paths will be
373 		 * added (otherwise -L paths are prepended to this list).
374 		 * Continue to process the remaining path string.
375 		 */
376 		if (path) {
377 			insert_lib = ofl->ofl_ulibdirs.tail;
378 			*path = '\0';
379 			++path;
380 			cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
381 			    FALSE);
382 			if (cp == (char *)S_ERROR)
383 				return (S_ERROR);
384 			else if (cp)
385 				eprintf(ofl->ofl_lml, ERR_WARNING,
386 				    MSG_INTL(MSG_LIB_MALFORM));
387 		}
388 	}
389 
390 	/*
391 	 * Add the default LIBPATH or any -YP supplied path.
392 	 */
393 	DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
394 	cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
395 	if (cp == (char *)S_ERROR)
396 		return (S_ERROR);
397 	else if (cp) {
398 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
399 		return (S_ERROR);
400 	}
401 	DBG_CALL(Dbg_libs_init(ofl->ofl_lml, &ofl->ofl_ulibdirs,
402 	    &ofl->ofl_dlibdirs));
403 	return (1);
404 }
405