1140072Strhodes/* 2140072Strhodes * Copyright (c) 1993 Paul Kranenburg 3140072Strhodes * All rights reserved. 4140072Strhodes * 5140072Strhodes * Redistribution and use in source and binary forms, with or without 6140072Strhodes * modification, are permitted provided that the following conditions 7140072Strhodes * are met: 8140072Strhodes * 1. Redistributions of source code must retain the above copyright 9140072Strhodes * notice, this list of conditions and the following disclaimer. 10140072Strhodes * 2. Redistributions in binary form must reproduce the above copyright 11140072Strhodes * notice, this list of conditions and the following disclaimer in the 12140072Strhodes * documentation and/or other materials provided with the distribution. 13140072Strhodes * 3. All advertising materials mentioning features or use of this software 14140072Strhodes * must display the following acknowledgement: 15140072Strhodes * This product includes software developed by Paul Kranenburg. 16140072Strhodes * 4. The name of the author may not be used to endorse or promote products 17140072Strhodes * derived from this software without specific prior written permission 18140072Strhodes * 19140072Strhodes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20140072Strhodes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21140072Strhodes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22140072Strhodes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23140072Strhodes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24140072Strhodes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25140072Strhodes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26140072Strhodes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27140072Strhodes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28140072Strhodes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29140072Strhodes * 30140072Strhodes * $FreeBSD$ 31140072Strhodes */ 32140072Strhodes 33140072Strhodes#include <sys/param.h> 34140072Strhodes#include <sys/types.h> 35140072Strhodes#include <sys/stat.h> 36140072Strhodes#include <sys/file.h> 37140072Strhodes#include <sys/time.h> 38140072Strhodes#include <a.out.h> 39140072Strhodes#include <ctype.h> 40140072Strhodes#include <dirent.h> 41140072Strhodes#include <err.h> 42140072Strhodes#include <fcntl.h> 43140072Strhodes#include <stdio.h> 44140072Strhodes#include <stdlib.h> 45140072Strhodes#include <string.h> 46140072Strhodes 47140072Strhodes#include <sys/link_aout.h> 48140072Strhodes#include "shlib.h" 49140072Strhodes#include "support.h" 50140072Strhodes 51140072Strhodes/* 52140072Strhodes * Standard directories to search for files specified by -l. 53140072Strhodes */ 54140072Strhodes#ifndef STANDARD_SEARCH_DIRS 55140072Strhodes#define STANDARD_SEARCH_DIRS "/usr/lib/aout" 56140072Strhodes#endif 57140072Strhodes 58140072Strhodes/* 59140072Strhodes * Actual vector of library search directories, 60140072Strhodes * including `-L'ed and LD_LIBRARY_PATH spec'd ones. 61140072Strhodes */ 62140072Strhodeschar **search_dirs; 63140072Strhodesint n_search_dirs; 64140072Strhodes 65140241Sdelphijconst char *standard_search_dirs[] = { 66140072Strhodes STANDARD_SEARCH_DIRS 67140072Strhodes}; 68140072Strhodes 69140072Strhodes 70140072Strhodesvoid 71140241Sdelphijadd_search_dir(const char *name) 72140072Strhodes{ 73140072Strhodes int n; 74140072Strhodes 75140072Strhodes for (n = 0; n < n_search_dirs; n++) 76140072Strhodes if (strcmp(search_dirs[n], name) == 0) 77140072Strhodes return; 78140072Strhodes n_search_dirs++; 79140072Strhodes search_dirs = (char **) 80140072Strhodes xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]); 81140072Strhodes search_dirs[n_search_dirs - 1] = strdup(name); 82140072Strhodes} 83140072Strhodes 84140072Strhodesvoid 85201217Sedadd_search_path(char *path) 86140072Strhodes{ 87140072Strhodes register char *cp, *dup; 88140072Strhodes 89140072Strhodes if (path == NULL) 90140072Strhodes return; 91140072Strhodes 92140072Strhodes /* Add search directories from `path' */ 93140072Strhodes path = dup = strdup(path); 94140072Strhodes while ((cp = strsep(&path, ":")) != NULL) 95140072Strhodes add_search_dir(cp); 96140072Strhodes free(dup); 97140072Strhodes} 98140072Strhodes 99140072Strhodesvoid 100201217Sedstd_search_path(void) 101140072Strhodes{ 102140072Strhodes int i, n; 103140072Strhodes 104140072Strhodes /* Append standard search directories */ 105140072Strhodes n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; 106140072Strhodes for (i = 0; i < n; i++) 107140072Strhodes add_search_dir(standard_search_dirs[i]); 108140072Strhodes} 109140072Strhodes 110140072Strhodes/* 111140072Strhodes * Return true if CP points to a valid dewey number. 112140072Strhodes * Decode and leave the result in the array DEWEY. 113140072Strhodes * Return the number of decoded entries in DEWEY. 114140072Strhodes */ 115140072Strhodes 116140072Strhodesint 117201217Sedgetdewey(int dewey[], char *cp) 118140072Strhodes{ 119140072Strhodes int i, n; 120140072Strhodes 121140072Strhodes for (n = 0, i = 0; i < MAXDEWEY; i++) { 122140072Strhodes if (*cp == '\0') 123140072Strhodes break; 124140072Strhodes 125140072Strhodes if (*cp == '.') cp++; 126140072Strhodes if (!isdigit(*cp)) 127140072Strhodes return 0; 128140072Strhodes 129140072Strhodes dewey[n++] = strtol(cp, &cp, 10); 130140072Strhodes } 131140072Strhodes 132140072Strhodes return n; 133140072Strhodes} 134140072Strhodes 135140072Strhodes/* 136140072Strhodes * Compare two dewey arrays. 137140072Strhodes * Return -1 if `d1' represents a smaller value than `d2'. 138140072Strhodes * Return 1 if `d1' represents a greater value than `d2'. 139140072Strhodes * Return 0 if equal. 140140072Strhodes */ 141140072Strhodesint 142201217Sedcmpndewey(int d1[], int n1, int d2[], int n2) 143140072Strhodes{ 144140072Strhodes register int i; 145140072Strhodes 146140072Strhodes for (i = 0; i < n1 && i < n2; i++) { 147140072Strhodes if (d1[i] < d2[i]) 148140072Strhodes return -1; 149140072Strhodes if (d1[i] > d2[i]) 150140072Strhodes return 1; 151140072Strhodes } 152140072Strhodes 153140072Strhodes if (n1 == n2) 154140072Strhodes return 0; 155140072Strhodes 156140072Strhodes if (i == n1) 157140072Strhodes return -1; 158140072Strhodes 159140072Strhodes if (i == n2) 160140072Strhodes return 1; 161140072Strhodes 162140072Strhodes errx(1, "cmpndewey: cant happen"); 163140072Strhodes return 0; 164140072Strhodes} 165140072Strhodes 166140072Strhodes/* 167140072Strhodes * Search directories for a shared library matching the given 168140072Strhodes * major and minor version numbers. See search_lib_dir() below for 169140072Strhodes * the detailed matching rules. 170140072Strhodes * 171140072Strhodes * As soon as a directory with an acceptable match is found, the search 172140072Strhodes * terminates. Subsequent directories are not searched for a better 173140072Strhodes * match. This is in conformance with the SunOS searching rules. Also, 174140072Strhodes * it avoids a lot of directory searches that are virtually guaranteed to 175140072Strhodes * be fruitless. 176140072Strhodes * 177140072Strhodes * The return value is a full pathname to the matching library. The 178140072Strhodes * string is dynamically allocated. If no matching library is found, the 179140072Strhodes * function returns NULL. 180140072Strhodes */ 181140072Strhodes 182140072Strhodeschar * 183201217Sedfindshlib(char *name, int *majorp, int *minorp, int do_dot_a) 184140072Strhodes{ 185140072Strhodes int i; 186140072Strhodes 187140072Strhodes for (i = 0; i < n_search_dirs; i++) { 188140072Strhodes char *path; 189140072Strhodes 190140072Strhodes path = search_lib_dir(search_dirs[i], name, majorp, minorp, 191140072Strhodes do_dot_a); 192140072Strhodes if(path != NULL) 193140072Strhodes return path; 194140072Strhodes } 195140072Strhodes 196140072Strhodes return NULL; 197140072Strhodes} 198140072Strhodes 199140072Strhodes/* 200140072Strhodes * Search library directories for a file with the given name. The 201140072Strhodes * return value is a full pathname to the matching file. The string 202140072Strhodes * is dynamically allocated. If no matching file is found, the function 203140072Strhodes * returns NULL. 204140072Strhodes */ 205140072Strhodes 206140072Strhodeschar * 207201217Sedfind_lib_file(const char *name) 208140072Strhodes{ 209140072Strhodes int i; 210140072Strhodes 211140072Strhodes for (i = 0; i < n_search_dirs; i++) { 212140072Strhodes char *path = concat(search_dirs[i], "/", name); 213140072Strhodes struct stat sb; 214140072Strhodes 215140072Strhodes if (lstat(path, &sb) != -1) /* We found it */ 216140072Strhodes return path; 217140072Strhodes 218140072Strhodes free(path); 219140072Strhodes } 220140072Strhodes 221140072Strhodes return NULL; 222140072Strhodes} 223140072Strhodes 224140072Strhodes/* 225140072Strhodes * Search a given directory for a library (preferably shared) satisfying 226140072Strhodes * the given criteria. 227140072Strhodes * 228140072Strhodes * The matching rules are as follows: 229140072Strhodes * 230140072Strhodes * if(*majorp == -1) 231140072Strhodes * find the library with the highest major version; 232140072Strhodes * else 233140072Strhodes * insist on a major version identical to *majorp; 234140072Strhodes * 235140072Strhodes * Always find the library with the highest minor version; 236140072Strhodes * if(*minorp != -1) 237140072Strhodes * insist on a minor version >= *minorp; 238140072Strhodes * 239140072Strhodes * It is invalid to specify a specific minor number while wildcarding 240140072Strhodes * the major number. 241140072Strhodes * 242140072Strhodes * The actual major and minor numbers found are returned via the pointer 243140072Strhodes * arguments. 244140072Strhodes * 245140072Strhodes * A suitable shared library is always preferred over a static (.a) library. 246140072Strhodes * If do_dot_a is false, then a static library will not be accepted in 247140072Strhodes * any case. 248140072Strhodes * 249140072Strhodes * The return value is a full pathname to the matching library. The 250140072Strhodes * string is dynamically allocated. If no matching library is found, the 251140072Strhodes * function returns NULL. 252140072Strhodes */ 253140072Strhodes 254140072Strhodeschar * 255201217Sedsearch_lib_dir(char *dir, char *name, int *majorp, int *minorp, int do_dot_a) 256140072Strhodes{ 257140241Sdelphij size_t namelen; 258140072Strhodes DIR *dd; 259140072Strhodes struct dirent *dp; 260140072Strhodes int best_dewey[MAXDEWEY]; 261140072Strhodes int best_ndewey; 262140072Strhodes char dot_a_name[MAXNAMLEN+1]; 263140072Strhodes char dot_so_name[MAXNAMLEN+1]; 264140072Strhodes 265140072Strhodes if((dd = opendir(dir)) == NULL) 266140072Strhodes return NULL; 267140072Strhodes 268140072Strhodes namelen = strlen(name); 269140072Strhodes best_ndewey = 0; 270140072Strhodes dot_a_name[0] = '\0'; 271140072Strhodes dot_so_name[0] = '\0'; 272140072Strhodes 273140072Strhodes while((dp = readdir(dd)) != NULL) { 274140072Strhodes char *extension; 275140072Strhodes 276140072Strhodes if(strlen(dp->d_name) < 3 + namelen + 2 || /* lib+xxx+.a */ 277140072Strhodes strncmp(dp->d_name, "lib", 3) != 0 || 278140072Strhodes strncmp(dp->d_name + 3, name, namelen) != 0 || 279140072Strhodes dp->d_name[3+namelen] != '.') 280140072Strhodes continue; 281140072Strhodes 282140072Strhodes extension = dp->d_name + 3 + namelen + 1; /* a or so.* */ 283140072Strhodes 284140072Strhodes if(strncmp(extension, "so.", 3) == 0) { 285140072Strhodes int cur_dewey[MAXDEWEY]; 286140072Strhodes int cur_ndewey; 287140072Strhodes 288140072Strhodes cur_ndewey = getdewey(cur_dewey, extension+3); 289140072Strhodes if(cur_ndewey < 2) /* Too few version numbers */ 290140072Strhodes continue; 291140072Strhodes 292140072Strhodes if(*majorp != -1) { /* Need exact match on major */ 293140072Strhodes if(cur_dewey[0] != *majorp) 294140072Strhodes continue; 295140072Strhodes if(*minorp != -1) { /* Need minor >= minimum */ 296140072Strhodes if(cur_dewey[1] < *minorp) 297140072Strhodes continue; 298140072Strhodes } 299140072Strhodes } 300140072Strhodes 301140072Strhodes if(cmpndewey(cur_dewey, cur_ndewey, best_dewey, 302140072Strhodes best_ndewey) <= 0) /* No better than prior match */ 303140072Strhodes continue; 304140072Strhodes 305140072Strhodes /* We found a better match */ 306140072Strhodes strcpy(dot_so_name, dp->d_name); 307140072Strhodes bcopy(cur_dewey, best_dewey, 308140072Strhodes cur_ndewey * sizeof best_dewey[0]); 309140072Strhodes best_ndewey = cur_ndewey; 310140072Strhodes } else if(do_dot_a && strcmp(extension, "a") == 0) 311140072Strhodes strcpy(dot_a_name, dp->d_name); 312140072Strhodes } 313140072Strhodes closedir(dd); 314140072Strhodes 315140072Strhodes if(dot_so_name[0] != '\0') { 316140072Strhodes *majorp = best_dewey[0]; 317140072Strhodes *minorp = best_dewey[1]; 318140072Strhodes return concat(dir, "/", dot_so_name); 319140072Strhodes } 320140072Strhodes 321140072Strhodes if(dot_a_name[0] != '\0') 322140072Strhodes return concat(dir, "/", dot_a_name); 323140072Strhodes 324140072Strhodes return NULL; 325140072Strhodes} 326