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