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* 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 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* 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 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* 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