shlib.c revision 1.8
1/* $OpenBSD: shlib.c,v 1.8 2003/07/06 20:04:00 deraadt Exp $ */ 2/* $NetBSD: shlib.c,v 1.13 1998/04/04 01:00:29 fvdl Exp $ */ 3 4/* 5 * Copyright (c) 1993 Paul Kranenburg 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Paul Kranenburg. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 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 <ranlib.h> 41#include <a.out.h> 42#include <ctype.h> 43#include <dirent.h> 44#include <err.h> 45#include <fcntl.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <string.h> 49 50#include "ld.h" 51 52/* 53 * Standard directories to search for files specified by -l. 54 */ 55#ifndef STANDARD_SEARCH_DIRS 56#define STANDARD_SEARCH_DIRS "/usr/lib" 57#endif 58 59/* 60 * Actual vector of library search directories, 61 * including `-L'ed and LD_LIBRARY_PATH spec'd ones. 62 */ 63char **search_dirs; 64int n_search_dirs; 65 66char *standard_search_dirs[] = { 67 STANDARD_SEARCH_DIRS 68}; 69 70void 71add_search_dir(char *name) 72{ 73 int i, len; 74 75 len = strlen(name); 76 77 while (len > 1 && name[len - 1] == '/') 78 --len; 79 80 for (i = 0; i < n_search_dirs; i++) 81 if (strlen(search_dirs[i]) == len && 82 !strncmp(search_dirs[i], name, len)) 83 return; 84 n_search_dirs++; 85 search_dirs = (char **) 86 xrealloc(search_dirs, n_search_dirs * sizeof search_dirs[0]); 87 search_dirs[n_search_dirs - 1] = xmalloc(++len); 88 (void)strlcpy(search_dirs[n_search_dirs - 1], name, len); 89} 90 91void 92remove_search_dir(char *name) 93{ 94 int i, len; 95 96 len = strlen(name); 97 98 while (len > 1 && name[len - 1] == '/') 99 --len; 100 101 for (i = 0; i < n_search_dirs; i++) { 102 if (strlen(search_dirs[i]) != len || 103 strncmp(search_dirs[i], name, len)) 104 continue; 105 free(search_dirs[i]); 106 if (i < (n_search_dirs - 1)) 107 bcopy(&search_dirs[i+1], &search_dirs[i], 108 (n_search_dirs - i - 1) * sizeof search_dirs[0]); 109 n_search_dirs--; 110 search_dirs = (char **)xrealloc(search_dirs, 111 n_search_dirs * sizeof search_dirs[0]); 112 break; 113 } 114} 115 116void 117add_search_path(char *path) 118{ 119 char *cp, *dup; 120 121 if (path == NULL) 122 return; 123 124 /* Add search directories from `path' */ 125 path = dup = strdup(path); 126 while ((cp = strsep(&path, ":")) != NULL) 127 add_search_dir(cp); 128 free(dup); 129} 130 131static void 132remove_search_path(char *path) 133{ 134 char *cp, *dup; 135 136 if (path == NULL) 137 return; 138 139 /* Remove search directories from `path' */ 140 path = dup = strdup(path); 141 while ((cp = strsep(&path, ":")) != NULL) 142 remove_search_dir(cp); 143 free(dup); 144} 145 146void 147std_search_path(void) 148{ 149 int i, n; 150 151 /* Append standard search directories */ 152 n = sizeof standard_search_dirs / sizeof standard_search_dirs[0]; 153 for (i = 0; i < n; i++) 154 add_search_dir(standard_search_dirs[i]); 155} 156 157/* 158 * Return true if CP points to a valid dewey number. 159 * Decode and leave the result in the array DEWEY. 160 * Return the number of decoded entries in DEWEY. 161 */ 162 163int 164getdewey(int dewey[], char *cp) 165{ 166 int i, n; 167 168 for (n = 0, i = 0; i < MAXDEWEY; i++) { 169 if (*cp == '\0') 170 break; 171 172 if (*cp == '.') cp++; 173#ifdef SUNOS_LIB_COMPAT 174 if (!(isdigit)(*cp)) 175#else 176 if (!isdigit(*cp)) 177#endif 178 return 0; 179 180 dewey[n++] = strtol(cp, &cp, 10); 181 } 182 return n; 183} 184 185/* 186 * Compare two dewey arrays. 187 * Return -1 if `d1' represents a smaller value than `d2'. 188 * Return 1 if `d1' represents a greater value than `d2'. 189 * Return 0 if equal. 190 */ 191int 192cmpndewey(int d1[], int n1, int d2[], int n2) 193{ 194 int i; 195 196 for (i = 0; i < n1 && i < n2; i++) { 197 if (d1[i] < d2[i]) 198 return -1; 199 if (d1[i] > d2[i]) 200 return 1; 201 } 202 if (n1 == n2) 203 return 0; 204 if (i == n1) 205 return -1; 206 if (i == n2) 207 return 1; 208 errx(1, "cmpndewey: cant happen"); 209 return 0; 210} 211 212/* 213 * Search directories for a shared library matching the given 214 * major and minor version numbers. 215 * 216 * MAJOR == -1 && MINOR == -1 --> find highest version 217 * MAJOR != -1 && MINOR == -1 --> find highest minor version 218 * MAJOR == -1 && MINOR != -1 --> invalid 219 * MAJOR != -1 && MINOR != -1 --> find highest micro version 220 */ 221 222/* Not interested in devices right now... */ 223#undef major 224#undef minor 225 226static char * 227findshlib(char *name, int *majorp, int *minorp, int do_dot_a) 228{ 229 int major = *majorp, minor = *minorp, ndewey, i, len; 230 int dewey[MAXDEWEY], tmp[MAXDEWEY]; 231 char *lname; 232 233 len = strlen(name) + sizeof("lib"); 234 lname = (char *)alloca(len); 235 snprintf(lname, len, "lib%s", name); 236 237 ndewey = 0; 238 239 for (i = 0; i < n_search_dirs; i++) { 240 struct dirent *dp; 241 char *path = NULL; 242 DIR *dd; 243 244 dd = opendir(search_dirs[i]); 245 if (dd == NULL) 246 continue; 247 248 while ((dp = readdir(dd)) != NULL) { 249 int n; 250 251 if (do_dot_a && path == NULL && 252 dp->d_namlen == len + 2 && 253 strncmp(dp->d_name, lname, len) == 0 && 254 (dp->d_name+len)[0] == '.' && 255 (dp->d_name+len)[1] == 'a') 256 path = concat(search_dirs[i], "/", dp->d_name); 257 258 if (dp->d_namlen < len + 4) 259 continue; 260 if (strncmp(dp->d_name, lname, len) != 0) 261 continue; 262 if (strncmp(dp->d_name+len, ".so.", 4) != 0) 263 continue; 264 265 if ((n = getdewey(tmp, dp->d_name+len+4)) == 0) 266 continue; 267 268 /* skip inappropriate versions. */ 269 if (major != -1) { 270 if (tmp[0] != major) 271 continue; 272 if (n != 1 && minor != -1 && tmp[1] < minor) 273 continue; 274 } 275 276 if (cmpndewey(tmp, n, dewey, ndewey) <= 0) 277 continue; 278 279 /* We have a better version */ 280 if (path) 281 free(path); 282 path = concat(search_dirs[i], "/", dp->d_name); 283 bcopy(tmp, dewey, sizeof(dewey)); 284 ndewey = n; 285 *majorp = dewey[0]; 286 *minorp = dewey[1]; 287 } 288 closedir(dd); 289 290 /* There's a lib in this dir; take it. */ 291 if (path != NULL) 292 return path; 293 } 294 return NULL; 295} 296