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