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