shlib.c revision 140072
1/* 2 * Copyright (c) 1993 Paul Kranenburg 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Paul Kranenburg. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $FreeBSD: head/libexec/rtld-aout/shlib.c 140072 2005-01-11 16:40:29Z trhodes $ 31 */ 32 33#include <sys/param.h> 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <sys/file.h> 37#include <sys/time.h> 38#include <a.out.h> 39#include <ctype.h> 40#include <dirent.h> 41#include <err.h> 42#include <fcntl.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46 47#include <sys/link_aout.h> 48#include "shlib.h" 49#include "support.h" 50 51/* 52 * Standard directories to search for files specified by -l. 53 */ 54#ifndef STANDARD_SEARCH_DIRS 55#define STANDARD_SEARCH_DIRS "/usr/lib/aout" 56#endif 57 58/* 59 * Actual vector of library search directories, 60 * including `-L'ed and LD_LIBRARY_PATH spec'd ones. 61 */ 62char **search_dirs; 63int n_search_dirs; 64 65char *standard_search_dirs[] = { 66 STANDARD_SEARCH_DIRS 67}; 68 69 70void 71add_search_dir(name) 72 char *name; 73{ 74 int n; 75 76 for (n = 0; n < n_search_dirs; n++) 77 if (strcmp(search_dirs[n], name) == 0) 78 return; 79 n_search_dirs++; 80 search_dirs = (char **) 81 xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]); 82 search_dirs[n_search_dirs - 1] = strdup(name); 83} 84 85void 86add_search_path(path) 87char *path; 88{ 89 register char *cp, *dup; 90 91 if (path == NULL) 92 return; 93 94 /* Add search directories from `path' */ 95 path = dup = strdup(path); 96 while ((cp = strsep(&path, ":")) != NULL) 97 add_search_dir(cp); 98 free(dup); 99} 100 101void 102std_search_path() 103{ 104 int i, n; 105 106 /* Append standard search directories */ 107 n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; 108 for (i = 0; i < n; i++) 109 add_search_dir(standard_search_dirs[i]); 110} 111 112/* 113 * Return true if CP points to a valid dewey number. 114 * Decode and leave the result in the array DEWEY. 115 * Return the number of decoded entries in DEWEY. 116 */ 117 118int 119getdewey(dewey, cp) 120int dewey[]; 121char *cp; 122{ 123 int i, n; 124 125 for (n = 0, i = 0; i < MAXDEWEY; i++) { 126 if (*cp == '\0') 127 break; 128 129 if (*cp == '.') cp++; 130 if (!isdigit(*cp)) 131 return 0; 132 133 dewey[n++] = strtol(cp, &cp, 10); 134 } 135 136 return n; 137} 138 139/* 140 * Compare two dewey arrays. 141 * Return -1 if `d1' represents a smaller value than `d2'. 142 * Return 1 if `d1' represents a greater value than `d2'. 143 * Return 0 if equal. 144 */ 145int 146cmpndewey(d1, n1, d2, n2) 147int d1[], d2[]; 148int n1, n2; 149{ 150 register int i; 151 152 for (i = 0; i < n1 && i < n2; i++) { 153 if (d1[i] < d2[i]) 154 return -1; 155 if (d1[i] > d2[i]) 156 return 1; 157 } 158 159 if (n1 == n2) 160 return 0; 161 162 if (i == n1) 163 return -1; 164 165 if (i == n2) 166 return 1; 167 168 errx(1, "cmpndewey: cant happen"); 169 return 0; 170} 171 172/* 173 * Search directories for a shared library matching the given 174 * major and minor version numbers. See search_lib_dir() below for 175 * the detailed matching rules. 176 * 177 * As soon as a directory with an acceptable match is found, the search 178 * terminates. Subsequent directories are not searched for a better 179 * match. This is in conformance with the SunOS searching rules. Also, 180 * it avoids a lot of directory searches that are virtually guaranteed to 181 * be fruitless. 182 * 183 * The return value is a full pathname to the matching library. The 184 * string is dynamically allocated. If no matching library is found, the 185 * function returns NULL. 186 */ 187 188char * 189findshlib(name, majorp, minorp, do_dot_a) 190char *name; 191int *majorp, *minorp; 192int do_dot_a; 193{ 194 int i; 195 196 for (i = 0; i < n_search_dirs; i++) { 197 char *path; 198 199 path = search_lib_dir(search_dirs[i], name, majorp, minorp, 200 do_dot_a); 201 if(path != NULL) 202 return path; 203 } 204 205 return NULL; 206} 207 208/* 209 * Search library directories for a file with the given name. The 210 * return value is a full pathname to the matching file. The string 211 * is dynamically allocated. If no matching file is found, the function 212 * returns NULL. 213 */ 214 215char * 216find_lib_file(name) 217 const char *name; 218{ 219 int i; 220 221 for (i = 0; i < n_search_dirs; i++) { 222 char *path = concat(search_dirs[i], "/", name); 223 struct stat sb; 224 225 if (lstat(path, &sb) != -1) /* We found it */ 226 return path; 227 228 free(path); 229 } 230 231 return NULL; 232} 233 234/* 235 * Search a given directory for a library (preferably shared) satisfying 236 * the given criteria. 237 * 238 * The matching rules are as follows: 239 * 240 * if(*majorp == -1) 241 * find the library with the highest major version; 242 * else 243 * insist on a major version identical to *majorp; 244 * 245 * Always find the library with the highest minor version; 246 * if(*minorp != -1) 247 * insist on a minor version >= *minorp; 248 * 249 * It is invalid to specify a specific minor number while wildcarding 250 * the major number. 251 * 252 * The actual major and minor numbers found are returned via the pointer 253 * arguments. 254 * 255 * A suitable shared library is always preferred over a static (.a) library. 256 * If do_dot_a is false, then a static library will not be accepted in 257 * any case. 258 * 259 * The return value is a full pathname to the matching library. The 260 * string is dynamically allocated. If no matching library is found, the 261 * function returns NULL. 262 */ 263 264char * 265search_lib_dir(dir, name, majorp, minorp, do_dot_a) 266 char *dir; 267 char *name; 268 int *majorp; 269 int *minorp; 270 int do_dot_a; 271{ 272 int namelen; 273 DIR *dd; 274 struct dirent *dp; 275 int best_dewey[MAXDEWEY]; 276 int best_ndewey; 277 char dot_a_name[MAXNAMLEN+1]; 278 char dot_so_name[MAXNAMLEN+1]; 279 280 if((dd = opendir(dir)) == NULL) 281 return NULL; 282 283 namelen = strlen(name); 284 best_ndewey = 0; 285 dot_a_name[0] = '\0'; 286 dot_so_name[0] = '\0'; 287 288 while((dp = readdir(dd)) != NULL) { 289 char *extension; 290 291 if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */ 292 strncmp(dp->d_name, "lib", 3) != 0 || 293 strncmp(dp->d_name + 3, name, namelen) != 0 || 294 dp->d_name[3+namelen] != '.') 295 continue; 296 297 extension = dp->d_name + 3 + namelen + 1; /* a or so.* */ 298 299 if(strncmp(extension, "so.", 3) == 0) { 300 int cur_dewey[MAXDEWEY]; 301 int cur_ndewey; 302 303 cur_ndewey = getdewey(cur_dewey, extension+3); 304 if(cur_ndewey < 2) /* Too few version numbers */ 305 continue; 306 307 if(*majorp != -1) { /* Need exact match on major */ 308 if(cur_dewey[0] != *majorp) 309 continue; 310 if(*minorp != -1) { /* Need minor >= minimum */ 311 if(cur_dewey[1] < *minorp) 312 continue; 313 } 314 } 315 316 if(cmpndewey(cur_dewey, cur_ndewey, best_dewey, 317 best_ndewey) <= 0) /* No better than prior match */ 318 continue; 319 320 /* We found a better match */ 321 strcpy(dot_so_name, dp->d_name); 322 bcopy(cur_dewey, best_dewey, 323 cur_ndewey * sizeof best_dewey[0]); 324 best_ndewey = cur_ndewey; 325 } else if(do_dot_a && strcmp(extension, "a") == 0) 326 strcpy(dot_a_name, dp->d_name); 327 } 328 closedir(dd); 329 330 if(dot_so_name[0] != '\0') { 331 *majorp = best_dewey[0]; 332 *minorp = best_dewey[1]; 333 return concat(dir, "/", dot_so_name); 334 } 335 336 if(dot_a_name[0] != '\0') 337 return concat(dir, "/", dot_a_name); 338 339 return NULL; 340} 341