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