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