xref: /illumos-gate/usr/src/cmd/sgs/libld/common/ldlibs.c (revision e9af4bc0b1cc30cea75d6ad4aa2fde97d985e9be)
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 2009 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  * Define a list index for "-L" processing.  By default, "-L" search paths are
45  * inserted at the beginning of the associated search list.  However, should a
46  * ";" be discovered in a LD_LIBRARY_PATH listing, then any new "-L" search
47  * paths are inserted following the ";".
48  */
49 static Aliste	Lidx = 0;
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(Ofl_desc *ofl, 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(ofl->ofl_lml, Llibdir,
69 			    path, index));
70 			return (Llibdir);
71 		}
72 	} else if (index == YUDIR) {
73 		if (Ulibdir) {
74 			/*
75 			 * User supplied "-YU,libdir", this is the pathname that
76 			 * corresponds for compatibility to -YU (as defined in
77 			 * sgs/include/paths.h)
78 			 */
79 			DBG_CALL(Dbg_libs_ylu(ofl->ofl_lml, Ulibdir,
80 			    path, index));
81 			return (Ulibdir);
82 		}
83 	}
84 	return (path);
85 }
86 
87 static char *
88 process_lib_path(Ofl_desc *ofl, APlist **apl, char *path, Boolean subsflag)
89 {
90 	int	i;
91 	char	*cp;
92 	Boolean	seenflg = FALSE;
93 	char	*dot = (char *)MSG_ORIG(MSG_STR_DOT);
94 
95 	for (i = YLDIR; i; i++) {
96 		cp = strpbrk(path, MSG_ORIG(MSG_STR_PATHTOK));
97 		if (cp == NULL) {
98 			if (*path == '\0') {
99 				if (seenflg)
100 					if (aplist_append(apl, (subsflag ?
101 					    compat_YL_YU(ofl, dot, i) : dot),
102 					    AL_CNT_OFL_LIBDIRS) == NULL)
103 						return ((char *)S_ERROR);
104 
105 			} else if (aplist_append(apl, (subsflag ?
106 			    compat_YL_YU(ofl, path, i) : path),
107 			    AL_CNT_OFL_LIBDIRS) == NULL) {
108 				return ((char *)S_ERROR);
109 			}
110 			return (cp);
111 		}
112 
113 		if (*cp == ':') {
114 			*cp = '\0';
115 			if (cp == path) {
116 				if (aplist_append(apl, (subsflag ?
117 				    compat_YL_YU(ofl, dot, i) : dot),
118 				    AL_CNT_OFL_LIBDIRS) == NULL)
119 					return ((char *)S_ERROR);
120 
121 			} else if (aplist_append(apl, (subsflag ?
122 			    compat_YL_YU(ofl, path, i) : path),
123 			    AL_CNT_OFL_LIBDIRS) == NULL) {
124 				return ((char *)S_ERROR);
125 			}
126 			path = cp + 1;
127 			seenflg = TRUE;
128 			continue;
129 		}
130 
131 		/* case ";" */
132 
133 		if (cp != path) {
134 			if (aplist_append(apl, (subsflag ?
135 			    compat_YL_YU(ofl, path, i) : path),
136 			    AL_CNT_OFL_LIBDIRS) == NULL)
137 				return ((char *)S_ERROR);
138 		} else {
139 			if (seenflg)
140 				if (aplist_append(apl, (subsflag ?
141 				    compat_YL_YU(ofl, dot, i) : dot),
142 				    AL_CNT_OFL_LIBDIRS) == NULL)
143 					return ((char *)S_ERROR);
144 		}
145 		return (cp);
146 	}
147 	/* NOTREACHED */
148 	return (NULL);	/* keep gcc happy */
149 }
150 
151 /*
152  * adds the indicated path to those to be searched for libraries.
153  */
154 uintptr_t
155 ld_add_libdir(Ofl_desc *ofl, const char *path)
156 {
157 	if (aplist_insert(&ofl->ofl_ulibdirs, path,
158 	    AL_CNT_OFL_LIBDIRS, Lidx++) == NULL)
159 		return (S_ERROR);
160 
161 	/*
162 	 * As -l and -L options can be interspersed, print the library
163 	 * search paths each time a new path is added.
164 	 */
165 	DBG_CALL(Dbg_libs_update(ofl->ofl_lml, ofl->ofl_ulibdirs,
166 	    ofl->ofl_dlibdirs));
167 	return (1);
168 }
169 
170 /*
171  * Process a required library.  Combine the directory and filename, and then
172  * append either a `.so' or `.a' suffix and try opening the associated pathname.
173  */
174 static Ifl_desc *
175 find_lib_name(const char *dir, const char *file, Ofl_desc *ofl, Rej_desc *rej)
176 {
177 	int		fd;
178 	size_t		dlen;
179 	char		*_path, path[PATH_MAX + 2];
180 	const char	*_dir = dir;
181 	Ifl_desc	*ifl;
182 
183 	/*
184 	 * Determine the size of the directory.  The directory and filename are
185 	 * concatenated into the local buffer which is purposely larger than
186 	 * PATH_MAX.  Should a pathname be created that exceeds the system
187 	 * limit, the open() will catch it, and a suitable rejection message is
188 	 * saved.
189 	 */
190 	if ((dlen = strlen(dir)) == 0) {
191 		_dir = (char *)MSG_ORIG(MSG_STR_DOT);
192 		dlen = 1;
193 	}
194 	dlen++;
195 
196 	/*
197 	 * If we are in dynamic mode try and open the associated shared object.
198 	 */
199 	if (ofl->ofl_flags & FLG_OF_DYNLIBS) {
200 		(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_SO),
201 		    _dir, file);
202 		DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
203 		if ((fd = open(path, O_RDONLY)) != -1) {
204 
205 			if ((_path = libld_malloc(strlen(path) + 1)) == NULL)
206 				return ((Ifl_desc *)S_ERROR);
207 			(void) strcpy(_path, path);
208 
209 			ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
210 			    FLG_IF_NEEDED, rej);
211 			if (fd != -1)
212 				(void) close(fd);
213 			return (ifl);
214 
215 		} else if (errno != ENOENT) {
216 			/*
217 			 * If the open() failed for anything other than the
218 			 * file not existing, record the error condition.
219 			 */
220 			rej->rej_type = SGS_REJ_STR;
221 			rej->rej_str = strerror(errno);
222 			rej->rej_name = strdup(path);
223 		}
224 	}
225 
226 	/*
227 	 * If we are not in dynamic mode, or a shared object could not be
228 	 * located, try and open the associated archive.
229 	 */
230 	(void) snprintf(path, (PATH_MAX + 2), MSG_ORIG(MSG_STR_LIB_A),
231 	    _dir, file);
232 	DBG_CALL(Dbg_libs_l(ofl->ofl_lml, file, path));
233 	if ((fd = open(path, O_RDONLY)) != -1) {
234 
235 		if ((_path = libld_malloc(strlen(path) + 1)) == NULL)
236 			return ((Ifl_desc *)S_ERROR);
237 		(void) strcpy(_path, path);
238 
239 		ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
240 		    FLG_IF_NEEDED, rej);
241 		if (fd != -1)
242 			(void) close(fd);
243 		return (ifl);
244 
245 	} else if (errno != ENOENT) {
246 		/*
247 		 * If the open() failed for anything other than the
248 		 * file not existing, record the error condition.
249 		 */
250 		rej->rej_type = SGS_REJ_STR;
251 		rej->rej_str = strerror(errno);
252 		rej->rej_name = strdup(path);
253 	}
254 
255 	return (NULL);
256 }
257 
258 /*
259  * Take the abbreviated name of a library file (from -lfoo) and searches for the
260  * library.  The search path rules are:
261  *
262  *	o	use any user supplied paths, i.e. LD_LIBRARY_PATH and -L, then
263  *
264  *	o	use the default directories, i.e. LIBPATH or -YP.
265  *
266  * If we are in dynamic mode and -Bstatic is not in effect, first look for a
267  * shared object with full name: path/libfoo.so; then [or else] look for an
268  * archive with name: path/libfoo.a.  If no file is found, it's a fatal error,
269  * otherwise process the file appropriately depending on its type.
270  */
271 uintptr_t
272 ld_find_library(const char *name, Ofl_desc *ofl)
273 {
274 	Aliste		idx;
275 	char		*path;
276 	Ifl_desc	*ifl = 0;
277 	Rej_desc	rej = { 0 };
278 
279 	/*
280 	 * Search for this file in any user defined directories.
281 	 */
282 	for (APLIST_TRAVERSE(ofl->ofl_ulibdirs, idx, path)) {
283 		Rej_desc	_rej = { 0 };
284 
285 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == NULL) {
286 			if (_rej.rej_type && (rej.rej_type == 0))
287 				rej = _rej;
288 			continue;
289 		}
290 		return ((uintptr_t)ifl);
291 	}
292 
293 	/*
294 	 * Finally try the default library search directories.
295 	 */
296 	for (APLIST_TRAVERSE(ofl->ofl_dlibdirs, idx, path)) {
297 		Rej_desc	_rej = { 0 };
298 
299 		if ((ifl = find_lib_name(path, name, ofl, &_rej)) == NULL) {
300 			if (_rej.rej_type && (rej.rej_type == 0))
301 				rej = _rej;
302 			continue;
303 		}
304 		return ((uintptr_t)ifl);
305 	}
306 
307 	/*
308 	 * If we've got this far we haven't found a shared object or archive.
309 	 * If an object was found, but was rejected for some reason, print a
310 	 * diagnostic to that effect, otherwise generate a generic "not found"
311 	 * diagnostic.
312 	 */
313 	if (rej.rej_type) {
314 		Conv_reject_desc_buf_t rej_buf;
315 
316 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(reject[rej.rej_type]),
317 		    rej.rej_name ? rej.rej_name : MSG_INTL(MSG_STR_UNKNOWN),
318 		    conv_reject_desc(&rej, &rej_buf, ld_targ.t_m.m_mach));
319 	} else {
320 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND),
321 		    name);
322 	}
323 
324 	ofl->ofl_flags |= FLG_OF_FATAL;
325 	return (0);
326 }
327 
328 /*
329  * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
330  * specified), and set up the directory list from which to search for
331  * libraries.  From the man page:
332  *
333  *	LD_LIBRARY_PATH=dirlist1;dirlist2
334  * and
335  *	ld ... -Lpath1 ... -Lpathn ...
336  *
337  * results in a search order of:
338  *
339  *	dirlist1 path1 ... pathn dirlist2 LIBPATH
340  *
341  * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
342  * all taken as dirlist2.
343  */
344 uintptr_t
345 ld_lib_setup(Ofl_desc *ofl)
346 {
347 	char	*path, *cp = NULL;
348 
349 	/*
350 	 * Determine whether an LD_LIBRARY_PATH setting is in effect.
351 	 */
352 	if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
353 #if	defined(_ELF64)
354 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
355 #else
356 		if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
357 #endif
358 			cp  = getenv(MSG_ORIG(MSG_LD_LIBPATH));
359 	}
360 
361 	if ((cp != NULL) && (*cp != '\0')) {
362 		if ((path = libld_malloc(strlen(cp) + 1)) == NULL)
363 			return (S_ERROR);
364 		(void) strcpy(path, cp);
365 		DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
366 
367 		/*
368 		 * Process the first path string (anything up to a null or
369 		 * a `;');
370 		 */
371 		path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
372 
373 
374 		/*
375 		 * By default, -L paths are prepended to the library search
376 		 * path list, because Lidx == 0.  If a ';' is seen within an
377 		 * LD_LIBRARY_PATH string, change the insert index so that -L
378 		 * paths are added following the ';'.
379 		 */
380 		if (path) {
381 			Lidx = aplist_nitems(ofl->ofl_ulibdirs);
382 			*path = '\0';
383 			++path;
384 			cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
385 			    FALSE);
386 			if (cp == (char *)S_ERROR)
387 				return (S_ERROR);
388 			else if (cp)
389 				eprintf(ofl->ofl_lml, ERR_WARNING,
390 				    MSG_INTL(MSG_LIB_MALFORM));
391 		}
392 	}
393 
394 	/*
395 	 * Add the default LIBPATH or any -YP supplied path.
396 	 */
397 	DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
398 	cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
399 	if (cp == (char *)S_ERROR)
400 		return (S_ERROR);
401 	else if (cp) {
402 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
403 		return (S_ERROR);
404 	}
405 	DBG_CALL(Dbg_libs_init(ofl->ofl_lml, ofl->ofl_ulibdirs,
406 	    ofl->ofl_dlibdirs));
407 	return (1);
408 }
409