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 *
compat_YL_YU(Ofl_desc * ofl,char * path,int index)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 *
process_lib_path(Ofl_desc * ofl,APlist ** apl,char * path,Boolean subsflag)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
ld_add_libdir(Ofl_desc * ofl,const char * path)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
find_lib_name(const char * dir,const char * file,Ofl_desc * ofl,Rej_desc * rej)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
ld_find_library(const char * name,Ofl_desc * ofl)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 ld_eprintf(ofl, 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 ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_LIB_NOTFOUND), name);
320 }
321
322 return (0);
323 }
324
325 /*
326 * Inspect the LD_LIBRARY_PATH variable (if the -i options has not been
327 * specified), and set up the directory list from which to search for
328 * libraries. From the man page:
329 *
330 * LD_LIBRARY_PATH=dirlist1;dirlist2
331 * and
332 * ld ... -Lpath1 ... -Lpathn ...
333 *
334 * results in a search order of:
335 *
336 * dirlist1 path1 ... pathn dirlist2 LIBPATH
337 *
338 * If LD_LIBRARY_PATH has no `;' specified, the pathname(s) supplied are
339 * all taken as dirlist2.
340 */
341 uintptr_t
ld_lib_setup(Ofl_desc * ofl)342 ld_lib_setup(Ofl_desc *ofl)
343 {
344 char *path, *cp = NULL;
345
346 /*
347 * Determine whether an LD_LIBRARY_PATH setting is in effect.
348 */
349 if (!(ofl->ofl_flags & FLG_OF_IGNENV)) {
350 #if defined(_ELF64)
351 if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_64))) == NULL)
352 #else
353 if ((cp = getenv(MSG_ORIG(MSG_LD_LIBPATH_32))) == NULL)
354 #endif
355 cp = getenv(MSG_ORIG(MSG_LD_LIBPATH));
356 }
357
358 if (cp && cp[0]) {
359 if ((path = libld_malloc(strlen(cp) + 1)) == NULL)
360 return (S_ERROR);
361 (void) strcpy(path, cp);
362 DBG_CALL(Dbg_libs_path(ofl->ofl_lml, path, LA_SER_DEFAULT, 0));
363
364 /*
365 * Process the first path string (anything up to a null or
366 * a `;');
367 */
368 path = process_lib_path(ofl, &ofl->ofl_ulibdirs, path, FALSE);
369
370
371 /*
372 * By default, -L paths are prepended to the library search
373 * path list, because Lidx == 0. If a ';' is seen within an
374 * LD_LIBRARY_PATH string, change the insert index so that -L
375 * paths are added following the ';'.
376 */
377 if (path) {
378 Lidx = aplist_nitems(ofl->ofl_ulibdirs);
379 *path = '\0';
380 ++path;
381 cp = process_lib_path(ofl, &ofl->ofl_ulibdirs, path,
382 FALSE);
383 if (cp == (char *)S_ERROR)
384 return (S_ERROR);
385 else if (cp)
386 ld_eprintf(ofl, ERR_WARNING,
387 MSG_INTL(MSG_LIB_MALFORM));
388 }
389 }
390
391 /*
392 * Add the default LIBPATH or any -YP supplied path.
393 */
394 DBG_CALL(Dbg_libs_yp(ofl->ofl_lml, Plibpath));
395 cp = process_lib_path(ofl, &ofl->ofl_dlibdirs, Plibpath, TRUE);
396 if (cp == (char *)S_ERROR)
397 return (S_ERROR);
398 else if (cp) {
399 ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_LIB_BADYP));
400 return (S_ERROR);
401 }
402 DBG_CALL(Dbg_libs_init(ofl->ofl_lml, ofl->ofl_ulibdirs,
403 ofl->ofl_dlibdirs));
404 return (1);
405 }
406