1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1997-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 */
25
26 #define _DLLINFO_PRIVATE_ \
27 char* sib[3]; \
28 char sibbuf[64]; \
29 char envbuf[64];
30
31 #define _DLLSCAN_PRIVATE_ \
32 Dllent_t entry; \
33 Uniq_t* uniq; \
34 int flags; \
35 Vmalloc_t* vm; \
36 Dt_t* dict; \
37 Dtdisc_t disc; \
38 FTS* fts; \
39 FTSENT* ent; \
40 Sfio_t* tmp; \
41 char** sb; \
42 char** sp; \
43 char* pb; \
44 char* pp; \
45 char* pe; \
46 int off; \
47 int prelen; \
48 int suflen; \
49 char** lib; \
50 char nam[64]; \
51 char pat[64]; \
52 char buf[64];
53
54 #define DLL_MATCH_DONE 0x8000
55 #define DLL_MATCH_NAME 0x4000
56 #define DLL_MATCH_VERSION 0x2000
57
58 #include <ast.h>
59 #include <cdt.h>
60 #include <ctype.h>
61 #include <error.h>
62 #include <fts.h>
63 #include <vmalloc.h>
64
65 typedef struct Uniq_s
66 {
67 Dtlink_t link;
68 char name[1];
69 } Uniq_t;
70
71 #include <dlldefs.h>
72
73 static char bin[] = "bin";
74 static char lib[] = "lib";
75
76 /*
77 * we need a sibling dir in PATH to search for dlls
78 * the confstr LIBPATH provides the local info
79 *
80 * <sibling-dir>[:<env-var>[:<host-pattern>]][,...]
81 *
82 * if <host-pattern> is present then it must match confstr HOSTTYPE
83 */
84
85 Dllinfo_t*
dllinfo(void)86 dllinfo(void)
87 {
88 register char* s;
89 register char* h;
90 char* d;
91 char* v;
92 char* p;
93 int dn;
94 int vn;
95 int pn;
96 char pat[256];
97
98 static Dllinfo_t info;
99
100 if (!info.sibling)
101 {
102 info.sibling = info.sib;
103 if (*(s = astconf("LIBPATH", NiL, NiL)))
104 {
105 while (*s == ':' || *s == ',')
106 s++;
107 if (*s)
108 {
109 h = 0;
110 for (;;)
111 {
112 for (d = s; *s && *s != ':' && *s != ','; s++);
113 if (!(dn = s - d))
114 d = 0;
115 if (*s == ':')
116 {
117 for (v = ++s; *s && *s != ':' && *s != ','; s++);
118 if (!(vn = s - v))
119 v = 0;
120 if (*s == ':')
121 {
122 for (p = ++s; *s && *s != ':' && *s != ','; s++);
123 if (!(pn = s - p))
124 p = 0;
125 }
126 else
127 p = 0;
128 }
129 else
130 {
131 v = 0;
132 p = 0;
133 }
134 while (*s && *s++ != ',');
135 if (!*s || !p || !h && !*(h = astconf("HOSTTYPE", NiL, NiL)))
136 break;
137 if (pn >= sizeof(pat))
138 pn = sizeof(pat) - 1;
139 memcpy(pat, p, pn);
140 pat[pn] = 0;
141 if (strmatch(h, pat))
142 break;
143 }
144 if (d && dn < sizeof(info.sibbuf))
145 {
146 memcpy(info.sibbuf, d, dn);
147 info.sibling[0] = info.sibbuf;
148 }
149 if (v && vn < sizeof(info.envbuf))
150 {
151 memcpy(info.envbuf, v, vn);
152 info.env = info.envbuf;
153 }
154 }
155 }
156 if (!info.sibling[0] || streq(info.sibling[0], bin))
157 info.sibling[0] = bin;
158 if (!streq(info.sibling[0], lib))
159 info.sibling[1] = lib;
160 if (!info.env)
161 info.env = "LD_LIBRARY_PATH";
162 info.prefix = astconf("LIBPREFIX", NiL, NiL);
163 info.suffix = astconf("LIBSUFFIX", NiL, NiL);
164 if (streq(info.suffix, ".dll"))
165 info.flags |= DLL_INFO_PREVER;
166 else
167 info.flags |= DLL_INFO_DOTVER;
168 }
169 return &info;
170 }
171
172 /*
173 * fts version sort order
174 * higher versions appear first
175 */
176
177 static int
vercmp(FTSENT * const * ap,FTSENT * const * bp)178 vercmp(FTSENT* const* ap, FTSENT* const* bp)
179 {
180 register unsigned char* a = (unsigned char*)(*ap)->fts_name;
181 register unsigned char* b = (unsigned char*)(*bp)->fts_name;
182 register int n;
183 register int m;
184 char* e;
185
186 for (;;)
187 {
188 if (isdigit(*a) && isdigit(*b))
189 {
190 m = strtol((char*)a, &e, 10);
191 a = (unsigned char*)e;
192 n = strtol((char*)b, &e, 10);
193 b = (unsigned char*)e;
194 if (n -= m)
195 return n;
196 }
197 if (n = *a - *b)
198 return n;
199 if (!*a++)
200 return *b ? 0 : -1;
201 if (!*b++)
202 return 1;
203 }
204 /*NOTREACHED*/
205 }
206
207 /*
208 * open a scan stream
209 */
210
211 Dllscan_t*
dllsopen(const char * lib,const char * name,const char * version)212 dllsopen(const char* lib, const char* name, const char* version)
213 {
214 register char* s;
215 register char* t;
216 Dllscan_t* scan;
217 Dllinfo_t* info;
218 Vmalloc_t* vm;
219 int i;
220 int j;
221 int k;
222 char buf[32];
223
224 if (!(vm = vmopen(Vmdcheap, Vmlast, 0)))
225 return 0;
226 if (lib && *lib && (*lib != '-' || *(lib + 1)))
227 {
228 /*
229 * grab the local part of the library id
230 */
231
232 if (s = strrchr(lib, ':'))
233 lib = (const char*)(s + 1);
234 i = 2 * sizeof(char**) + strlen(lib) + 5;
235 }
236 else
237 {
238 lib = 0;
239 i = 0;
240 }
241 if (version && (!*version || *version == '-' && !*(version + 1)))
242 version = 0;
243 if (!(scan = vmnewof(vm, 0, Dllscan_t, 1, i)) || !(scan->tmp = sfstropen()))
244 {
245 vmclose(vm);
246 return 0;
247 }
248 scan->vm = vm;
249 info = dllinfo();
250 scan->flags = info->flags;
251 if (lib)
252 {
253 scan->lib = (char**)(scan + 1);
254 s = *scan->lib = (char*)(scan->lib + 2);
255 sfsprintf(s, i, "lib/%s", lib);
256 if (!version && streq(info->suffix, ".dylib"))
257 version = "0.0";
258 }
259 if (!name || !*name || *name == '-' && !*(name + 1))
260 {
261 name = (const char*)"?*";
262 scan->flags |= DLL_MATCH_NAME;
263 }
264 else if (t = strrchr(name, '/'))
265 {
266 if (!(scan->pb = vmnewof(vm, 0, char, t - (char*)name, 2)))
267 goto bad;
268 memcpy(scan->pb, name, t - (char*)name);
269 name = (const char*)(t + 1);
270 }
271 if (name)
272 {
273 i = strlen(name);
274 j = strlen(info->prefix);
275 if (!j || i > j && strneq(name, info->prefix, j))
276 {
277 k = strlen(info->suffix);
278 if (i > k && streq(name + i - k, info->suffix))
279 {
280 i -= j + k;
281 if (!(t = vmnewof(vm, 0, char, i, 1)))
282 goto bad;
283 memcpy(t, name + j, i);
284 t[i] = 0;
285 name = (const char*)t;
286 }
287 }
288 if (!version)
289 for (t = (char*)name; *t; t++)
290 if ((*t == '-' || *t == '.' || *t == '?') && isdigit(*(t + 1)))
291 {
292 if (*t != '-')
293 scan->flags |= DLL_MATCH_VERSION;
294 version = t + 1;
295 if (!(s = vmnewof(vm, 0, char, t - (char*)name, 1)))
296 goto bad;
297 memcpy(s, name, t - (char*)name);
298 name = (const char*)s;
299 break;
300 }
301 }
302 if (!version)
303 {
304 scan->flags |= DLL_MATCH_VERSION;
305 sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s", info->prefix, name, info->suffix);
306 }
307 else if (scan->flags & DLL_INFO_PREVER)
308 {
309 sfprintf(scan->tmp, "%s%s", info->prefix, name);
310 for (s = (char*)version; *s; s++)
311 if (isdigit(*s))
312 sfputc(scan->tmp, *s);
313 sfprintf(scan->tmp, "%s", info->suffix);
314 if (!(s = sfstruse(scan->tmp)))
315 goto bad;
316 sfsprintf(scan->nam, sizeof(scan->nam), "%s", s);
317 }
318 else
319 sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s.%s", info->prefix, name, info->suffix, version);
320 if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
321 {
322 if (scan->flags & DLL_INFO_PREVER)
323 {
324 if (!version)
325 version = "*([0-9_])";
326 else
327 {
328 t = buf;
329 for (s = (char*)version; *s; s++)
330 if (isdigit(*s) && t < &buf[sizeof(buf)-1])
331 *t++ = *s;
332 *t = 0;
333 version = (const char*)buf;
334 }
335 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s%s%s", info->prefix, name, version, info->suffix);
336 }
337 else if (version)
338 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(%s([-.])%s%s|%s.%s)", info->prefix, name, strchr(version, '.') ? "@" : "?", version, info->suffix, info->suffix, version);
339 else
340 {
341 version = "*([0-9.])";
342 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(?([-.])%s%s|%s%s)", info->prefix, name, version, info->suffix, info->suffix, version);
343 }
344 }
345 scan->sp = scan->sb = (scan->lib ? scan->lib : info->sibling);
346 scan->prelen = strlen(info->prefix);
347 scan->suflen = strlen(info->suffix);
348 return scan;
349 bad:
350 dllsclose(scan);
351 return 0;
352 }
353
354 /*
355 * close a scan stream
356 */
357
358 int
dllsclose(Dllscan_t * scan)359 dllsclose(Dllscan_t* scan)
360 {
361 if (!scan)
362 return -1;
363 if (scan->fts)
364 fts_close(scan->fts);
365 if (scan->dict)
366 dtclose(scan->dict);
367 if (scan->tmp)
368 sfclose(scan->tmp);
369 if (scan->vm)
370 vmclose(scan->vm);
371 return 0;
372 }
373
374 /*
375 * return the next scan stream entry
376 */
377
378 Dllent_t*
dllsread(register Dllscan_t * scan)379 dllsread(register Dllscan_t* scan)
380 {
381 register char* p;
382 register char* b;
383 register char* t;
384 register Uniq_t* u;
385 register int n;
386 register int m;
387
388 if (scan->flags & DLL_MATCH_DONE)
389 return 0;
390 again:
391 do
392 {
393 while (!scan->ent || !(scan->ent = scan->ent->fts_link))
394 {
395 if (scan->fts)
396 {
397 fts_close(scan->fts);
398 scan->fts = 0;
399 }
400 if (!scan->pb)
401 scan->pb = pathbin();
402 else if (!*scan->sp)
403 {
404 scan->sp = scan->sb;
405 if (!*scan->pe++)
406 return 0;
407 scan->pb = scan->pe;
408 }
409 for (p = scan->pp = scan->pb; *p && *p != ':'; p++)
410 if (*p == '/')
411 scan->pp = p;
412 scan->pe = p;
413 if (*scan->sp == bin)
414 scan->off = sfprintf(scan->tmp, "%-.*s", scan->pe - scan->pb, scan->pb);
415 else
416 scan->off = sfprintf(scan->tmp, "%-.*s/%s", scan->pp - scan->pb, scan->pb, *scan->sp);
417 scan->sp++;
418 if (!(scan->flags & DLL_MATCH_NAME))
419 {
420 sfprintf(scan->tmp, "/%s", scan->nam);
421 if (!(p = sfstruse(scan->tmp)))
422 return 0;
423 if (!eaccess(p, R_OK))
424 {
425 b = scan->nam;
426 goto found;
427 }
428 if (errno != ENOENT)
429 continue;
430 }
431 if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION))
432 {
433 sfstrseek(scan->tmp, scan->off, SEEK_SET);
434 if (!(t = sfstruse(scan->tmp)))
435 return 0;
436 if ((scan->fts = fts_open((char**)t, FTS_LOGICAL|FTS_NOPOSTORDER|FTS_ONEPATH, vercmp)) && (scan->ent = fts_read(scan->fts)) && (scan->ent = fts_children(scan->fts, FTS_NOSTAT)))
437 break;
438 }
439 }
440 } while (!strmatch(scan->ent->fts_name, scan->pat));
441 b = scan->ent->fts_name;
442 sfstrseek(scan->tmp, scan->off, SEEK_SET);
443 sfprintf(scan->tmp, "/%s", b);
444 if (!(p = sfstruse(scan->tmp)))
445 return 0;
446 found:
447 b = scan->buf + sfsprintf(scan->buf, sizeof(scan->buf), "%s", b + scan->prelen);
448 if (!(scan->flags & DLL_INFO_PREVER))
449 while (b > scan->buf)
450 {
451 if (!isdigit(*(b - 1)) && *(b - 1) != '.')
452 break;
453 b--;
454 }
455 b -= scan->suflen;
456 if (b > (scan->buf + 2) && (*(b - 1) == 'g' || *(b - 1) == 'O') && *(b - 2) == '-')
457 b -= 2;
458 n = m = 0;
459 for (t = b; t > scan->buf; t--)
460 if (isdigit(*(t - 1)))
461 n = 1;
462 else if (*(t - 1) != m)
463 {
464 if (*(t - 1) == '.' || *(t - 1) == '-' || *(t - 1) == '_')
465 {
466 n = 1;
467 if (m)
468 {
469 m = -1;
470 t--;
471 break;
472 }
473 m = *(t - 1);
474 }
475 else
476 break;
477 }
478 if (n)
479 {
480 if (isdigit(t[0]) && isdigit(t[1]) && !isdigit(t[2]))
481 n = (t[0] - '0') * 10 + (t[1] - '0');
482 else if (isdigit(t[1]) && isdigit(t[2]) && !isdigit(t[3]))
483 n = (t[1] - '0') * 10 + (t[2] - '0');
484 else
485 n = 0;
486 if (n && !(n & (n - 1)))
487 {
488 if (!isdigit(t[0]))
489 t++;
490 m = *(t += 2);
491 }
492 if (m || (scan->flags & DLL_INFO_PREVER))
493 b = t;
494 }
495 *b = 0;
496 if (!*(b = scan->buf))
497 goto again;
498 if (scan->uniq)
499 {
500 if (!scan->dict)
501 {
502 scan->disc.key = offsetof(Uniq_t, name);
503 scan->disc.size = 0;
504 scan->disc.link = offsetof(Uniq_t, link);
505 if (!(scan->dict = dtopen(&scan->disc, Dtset)))
506 return 0;
507 dtinsert(scan->dict, scan->uniq);
508 }
509 if (dtmatch(scan->dict, b))
510 goto again;
511 if (!(u = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
512 return 0;
513 strcpy(u->name, b);
514 dtinsert(scan->dict, u);
515 }
516 else if (!(scan->flags & DLL_MATCH_NAME))
517 scan->flags |= DLL_MATCH_DONE;
518 else if (!(scan->uniq = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b))))
519 return 0;
520 else
521 strcpy(scan->uniq->name, b);
522 scan->entry.name = b;
523 scan->entry.path = p;
524 errorf("dll", NiL, -1, "dllsread: %s bound to %s", b, p);
525 return &scan->entry;
526 }
527