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 2010 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 && 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