This is Paul K's latest set of ld changes. A commit was necessary at this
[unix-history] / gnu / usr.bin / ld / shlib.c
CommitLineData
1136f72d 1/*
6a61ea88
JH
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 * $Id: shlib.c,v 1.9 1994/01/29 02:03:15 jtc Exp $
1136f72d
PR
31 */
32
33#include <sys/param.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <sys/file.h>
39#include <sys/time.h>
40#include <fcntl.h>
41#include <string.h>
0f052032 42#include <ctype.h>
1136f72d
PR
43#include <dirent.h>
44#include <a.out.h>
45
46#include "ld.h"
47
0f052032
JH
48#ifdef SUNOS4
49char *strsep();
50#endif
51
1136f72d
PR
52/*
53 * Standard directories to search for files specified by -l.
54 */
55#ifndef STANDARD_SEARCH_DIRS
6a61ea88 56#define STANDARD_SEARCH_DIRS "/usr/lib", "/usr/X386/lib", "/usr/local/lib"
1136f72d
PR
57#endif
58
6a61ea88
JH
59/*
60 * Actual vector of library search directories,
61 * including `-L'ed and LD_LIBARAY_PATH spec'd ones.
62 */
63char **search_dirs;
64int n_search_dirs;
65
1136f72d
PR
66char *standard_search_dirs[] = {
67 STANDARD_SEARCH_DIRS
68};
69
1136f72d
PR
70
71void
72add_search_dir(name)
73 char *name;
74{
75 n_search_dirs++;
76 search_dirs = (char **)xrealloc(search_dirs,
77 n_search_dirs * sizeof(char *));
78 search_dirs[n_search_dirs - 1] = strdup(name);
79}
80
81void
82std_search_dirs(paths)
83char *paths;
84{
85 char *cp;
86 int i, n;
87
88 if (paths != NULL)
89 /* Add search directories from `paths' */
7fc7155d 90 while ((cp = strsep(&paths, ":")) != NULL) {
1136f72d 91 add_search_dir(cp);
7fc7155d
PR
92 if (paths)
93 *(paths-1) = ':';
1136f72d
PR
94 }
95
96 /* Append standard search directories */
97 n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
98 for (i = 0; i < n; i++)
99 add_search_dir(standard_search_dirs[i]);
100}
101
102/*
103 * Return true if CP points to a valid dewey number.
104 * Decode and leave the result in the array DEWEY.
105 * Return the number of decoded entries in DEWEY.
106 */
107
108int
109getdewey(dewey, cp)
110int dewey[];
111char *cp;
112{
113 int i, n;
114
115 for (n = 0, i = 0; i < MAXDEWEY; i++) {
116 if (*cp == '\0')
117 break;
118
119 if (*cp == '.') cp++;
120 if (!isdigit(*cp))
121 return 0;
122
123 dewey[n++] = strtol(cp, &cp, 10);
124 }
125
126 return n;
127}
128
129/*
130 * Compare two dewey arrays.
131 * Return -1 if `d1' represents a smaller value than `d2'.
132 * Return 1 if `d1' represents a greater value than `d2'.
133 * Return 0 if equal.
134 */
135int
136cmpndewey(d1, n1, d2, n2)
137int d1[], d2[];
138int n1, n2;
139{
140 int i;
141
142 for (i = 0; i < n1 && i < n2; i++) {
143 if (d1[i] < d2[i])
144 return -1;
145 if (d1[i] > d2[i])
146 return 1;
147 }
148
149 if (n1 == n2)
150 return 0;
151
152 if (i == n1)
153 return -1;
154
155 if (i == n2)
156 return 1;
157}
158
159/*
160 * Search directories for a shared library matching the given
161 * major and minor version numbers.
162 *
163 * MAJOR == -1 && MINOR == -1 --> find highest version
164 * MAJOR != -1 && MINOR == -1 --> find highest minor version
165 * MAJOR == -1 && MINOR != -1 --> invalid
166 * MAJOR != -1 && MINOR != -1 --> find highest micro version
167 */
168
169/* Not interested in devices right now... */
170#undef major
171#undef minor
172
173char *
0f052032 174findshlib(name, majorp, minorp, do_dot_a)
1136f72d
PR
175char *name;
176int *majorp, *minorp;
0f052032 177int do_dot_a;
1136f72d
PR
178{
179 int dewey[MAXDEWEY];
180 int ndewey;
181 int tmp[MAXDEWEY];
182 int i;
183 int len;
184 char *lname, *path = NULL;
185 int major = *majorp, minor = *minorp;
186
187 len = strlen(name);
188 lname = (char *)alloca(len + sizeof("lib"));
189 sprintf(lname, "lib%s", name);
190 len += 3;
191
192 ndewey = 0;
193
194 for (i = 0; i < n_search_dirs; i++) {
195 DIR *dd = opendir(search_dirs[i]);
196 struct dirent *dp;
0f052032 197 int found_dot_a = 0;
1136f72d
PR
198
199 if (dd == NULL)
200 continue;
201
202 while ((dp = readdir(dd)) != NULL) {
203 int n, j, might_take_it = 0;
204
0f052032
JH
205 if (do_dot_a && path == NULL &&
206 dp->d_namlen == len + 2 &&
207 strncmp(dp->d_name, lname, len) == 0 &&
208 (dp->d_name+len)[0] == '.' &&
209 (dp->d_name+len)[1] == 'a') {
210
211 path = concat(search_dirs[i], "/", dp->d_name);
212 found_dot_a = 1;
213 }
214
1136f72d
PR
215 if (dp->d_namlen < len + 4)
216 continue;
217 if (strncmp(dp->d_name, lname, len) != 0)
218 continue;
219 if (strncmp(dp->d_name+len, ".so.", 4) != 0)
220 continue;
221
222 if ((n = getdewey(tmp, dp->d_name+len+4)) == 0)
223 continue;
224
0f052032
JH
225 if (major != -1 && found_dot_a) { /* XXX */
226 free(path);
227 path = NULL;
228 found_dot_a = 0;
229 }
230
1136f72d
PR
231 if (major == -1 && minor == -1) {
232 might_take_it = 1;
233 } else if (major != -1 && minor == -1) {
234 if (tmp[0] == major)
235 might_take_it = 1;
236 } else if (major != -1 && minor != -1) {
237 if (tmp[0] == major)
238 if (n == 1 || tmp[1] >= minor)
239 might_take_it = 1;
240 }
241
242 if (!might_take_it)
243 continue;
244
245 if (cmpndewey(tmp, n, dewey, ndewey) <= 0)
246 continue;
247
248 /* We have a better version */
249 if (path)
250 free(path);
251 path = concat(search_dirs[i], "/", dp->d_name);
0f052032 252 found_dot_a = 0;
1136f72d
PR
253 bcopy(tmp, dewey, sizeof(dewey));
254 ndewey = n;
255 *majorp = dewey[0];
256 *minorp = dewey[1];
257 }
258 closedir(dd);
0f052032
JH
259
260 if (found_dot_a)
261 /*
262 * There's a .a archive here.
263 */
264 return path;
1136f72d
PR
265 }
266
267 return path;
268}