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