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$ 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 65static const char *standard_search_dirs[] = { 66 STANDARD_SEARCH_DIRS 67}; 68 69 70void 71add_search_dir(const char *name) 72{ 73 int n; 74 75 for (n = 0; n < n_search_dirs; n++) 76 if (strcmp(search_dirs[n], name) == 0) 77 return; 78 n_search_dirs++; 79 search_dirs = (char **) 80 xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]); 81 search_dirs[n_search_dirs - 1] = strdup(name); 82} 83 84void 85add_search_path(char *path) 86{ 87 register char *cp, *dup; 88 89 if (path == NULL) 90 return; 91 92 /* Add search directories from `path' */ 93 path = dup = strdup(path); 94 while ((cp = strsep(&path, ":")) != NULL) 95 add_search_dir(cp); 96 free(dup); 97} 98 99void 100std_search_path(void) 101{ 102 int i, n; 103 104 /* Append standard search directories */ 105 n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; 106 for (i = 0; i < n; i++) 107 add_search_dir(standard_search_dirs[i]); 108} 109 110/* 111 * Return true if CP points to a valid dewey number. 112 * Decode and leave the result in the array DEWEY. 113 * Return the number of decoded entries in DEWEY. 114 */ 115 116int 117getdewey(int dewey[], char *cp) 118{ 119 int i, n; 120 121 for (n = 0, i = 0; i < MAXDEWEY; i++) { 122 if (*cp == '\0') 123 break; 124 125 if (*cp == '.') cp++; 126 if (!isdigit(*cp)) 127 return 0; 128 129 dewey[n++] = strtol(cp, &cp, 10); 130 } 131 132 return n; 133} 134 135/* 136 * Compare two dewey arrays. 137 * Return -1 if `d1' represents a smaller value than `d2'. 138 * Return 1 if `d1' represents a greater value than `d2'. 139 * Return 0 if equal. 140 */ 141int 142cmpndewey(int d1[], int n1, int d2[], int n2) 143{ 144 register int i; 145 146 for (i = 0; i < n1 && i < n2; i++) { 147 if (d1[i] < d2[i]) 148 return -1; 149 if (d1[i] > d2[i]) 150 return 1; 151 } 152 153 if (n1 == n2) 154 return 0; 155 156 if (i == n1) 157 return -1; 158 159 if (i == n2) 160 return 1; 161 162 errx(1, "cmpndewey: can't happen"); 163 return 0; 164} 165 166/* 167 * Search directories for a shared library matching the given 168 * major and minor version numbers. See search_lib_dir() below for 169 * the detailed matching rules. 170 * 171 * As soon as a directory with an acceptable match is found, the search 172 * terminates. Subsequent directories are not searched for a better 173 * match. This is in conformance with the SunOS searching rules. Also, 174 * it avoids a lot of directory searches that are virtually guaranteed to 175 * be fruitless. 176 * 177 * The return value is a full pathname to the matching library. The 178 * string is dynamically allocated. If no matching library is found, the 179 * function returns NULL. 180 */ 181 182char * 183findshlib(char *name, int *majorp, int *minorp, int do_dot_a) 184{ 185 int i; 186 187 for (i = 0; i < n_search_dirs; i++) { 188 char *path; 189 190 path = search_lib_dir(search_dirs[i], name, majorp, minorp, 191 do_dot_a); 192 if(path != NULL) 193 return path; 194 } 195 196 return NULL; 197} 198 199/* 200 * Search library directories for a file with the given name. The 201 * return value is a full pathname to the matching file. The string 202 * is dynamically allocated. If no matching file is found, the function 203 * returns NULL. 204 */ 205 206char * 207find_lib_file(const char *name) 208{ 209 int i; 210 211 for (i = 0; i < n_search_dirs; i++) { 212 char *path = concat(search_dirs[i], "/", name); 213 struct stat sb; 214 215 if (lstat(path, &sb) != -1) /* We found it */ 216 return path; 217 218 free(path); 219 } 220 221 return NULL; 222} 223 224/* 225 * Search a given directory for a library (preferably shared) satisfying 226 * the given criteria. 227 * 228 * The matching rules are as follows: 229 * 230 * if(*majorp == -1) 231 * find the library with the highest major version; 232 * else 233 * insist on a major version identical to *majorp; 234 * 235 * Always find the library with the highest minor version; 236 * if(*minorp != -1) 237 * insist on a minor version >= *minorp; 238 * 239 * It is invalid to specify a specific minor number while wildcarding 240 * the major number. 241 * 242 * The actual major and minor numbers found are returned via the pointer 243 * arguments. 244 * 245 * A suitable shared library is always preferred over a static (.a) library. 246 * If do_dot_a is false, then a static library will not be accepted in 247 * any case. 248 * 249 * The return value is a full pathname to the matching library. The 250 * string is dynamically allocated. If no matching library is found, the 251 * function returns NULL. 252 */ 253 254char * 255search_lib_dir(char *dir, char *name, int *majorp, int *minorp, int do_dot_a) 256{ 257 size_t namelen; 258 DIR *dd; 259 struct dirent *dp; 260 int best_dewey[MAXDEWEY]; 261 int best_ndewey; 262 char dot_a_name[MAXNAMLEN+1]; 263 char dot_so_name[MAXNAMLEN+1]; 264 265 if((dd = opendir(dir)) == NULL) 266 return NULL; 267 268 namelen = strlen(name); 269 best_ndewey = 0; 270 dot_a_name[0] = '\0'; 271 dot_so_name[0] = '\0'; 272 273 while((dp = readdir(dd)) != NULL) { 274 char *extension; 275 276 if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */ 277 strncmp(dp->d_name, "lib", 3) != 0 || 278 strncmp(dp->d_name + 3, name, namelen) != 0 || 279 dp->d_name[3+namelen] != '.') 280 continue; 281 282 extension = dp->d_name + 3 + namelen + 1; /* a or so.* */ 283 284 if(strncmp(extension, "so.", 3) == 0) { 285 int cur_dewey[MAXDEWEY]; 286 int cur_ndewey; 287 288 cur_ndewey = getdewey(cur_dewey, extension+3); 289 if(cur_ndewey < 2) /* Too few version numbers */ 290 continue; 291 292 if(*majorp != -1) { /* Need exact match on major */ 293 if(cur_dewey[0] != *majorp) 294 continue; 295 if(*minorp != -1) { /* Need minor >= minimum */ 296 if(cur_dewey[1] < *minorp) 297 continue; 298 } 299 } 300 301 if(cmpndewey(cur_dewey, cur_ndewey, best_dewey, 302 best_ndewey) <= 0) /* No better than prior match */ 303 continue; 304 305 /* We found a better match */ 306 strcpy(dot_so_name, dp->d_name); 307 bcopy(cur_dewey, best_dewey, 308 cur_ndewey * sizeof best_dewey[0]); 309 best_ndewey = cur_ndewey; 310 } else if(do_dot_a && strcmp(extension, "a") == 0) 311 strcpy(dot_a_name, dp->d_name); 312 } 313 closedir(dd); 314 315 if(dot_so_name[0] != '\0') { 316 *majorp = best_dewey[0]; 317 *minorp = best_dewey[1]; 318 return concat(dir, "/", dot_so_name); 319 } 320 321 if(dot_a_name[0] != '\0') 322 return concat(dir, "/", dot_a_name); 323 324 return NULL; 325} 326