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