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