1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1997-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 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 char buf[32]; 221 222 if (!(vm = vmopen(Vmdcheap, Vmlast, 0))) 223 return 0; 224 if (lib && *lib && (*lib != '-' || *(lib + 1))) 225 { 226 /* 227 * grab the local part of the library id 228 */ 229 230 if (s = strrchr(lib, ':')) 231 lib = (const char*)(s + 1); 232 i = 2 * sizeof(char**) + strlen(lib) + 5; 233 } 234 else 235 { 236 lib = 0; 237 i = 0; 238 } 239 if (version && *version && (*version != '-' || *(version + 1))) 240 version = 0; 241 if (!(scan = vmnewof(vm, 0, Dllscan_t, 1, i)) || !(scan->tmp = sfstropen())) 242 { 243 vmclose(vm); 244 return 0; 245 } 246 scan->vm = vm; 247 info = dllinfo(); 248 scan->flags = info->flags; 249 if (lib) 250 { 251 scan->lib = (char**)(scan + 1); 252 s = *scan->lib = (char*)(scan->lib + 2); 253 sfsprintf(s, i, "lib/%s", lib); 254 if (!version && streq(info->suffix, ".dylib")) 255 version = "0.0"; 256 } 257 if (!name || !*name || *name == '-' && !*(name + 1)) 258 { 259 name = (const char*)"?*"; 260 scan->flags |= DLL_MATCH_NAME; 261 } 262 else if (t = strrchr(name, '/')) 263 { 264 if (!(scan->pb = vmnewof(vm, 0, char, t - (char*)name, 2))) 265 goto bad; 266 memcpy(scan->pb, name, t - (char*)name); 267 name = (const char*)(t + 1); 268 } 269 if (name && !version) 270 for (t = (char*)name; *t; t++) 271 if ((*t == '-' || *t == '.' || *t == '?') && isdigit(*(t + 1))) 272 { 273 if (*t != '-') 274 scan->flags |= DLL_MATCH_VERSION; 275 version = t + 1; 276 if (!(s = vmnewof(vm, 0, char, t - (char*)name, 1))) 277 goto bad; 278 memcpy(s, name, t - (char*)name); 279 name = (const char*)s; 280 break; 281 } 282 if (!version) 283 { 284 scan->flags |= DLL_MATCH_VERSION; 285 sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s", info->prefix, name, info->suffix); 286 } 287 else if (scan->flags & DLL_INFO_PREVER) 288 { 289 sfprintf(scan->tmp, "%s%s", info->prefix, name); 290 for (s = (char*)version; *s; s++) 291 if (isdigit(*s)) 292 sfputc(scan->tmp, *s); 293 sfprintf(scan->tmp, "%s", info->suffix); 294 if (!(s = sfstruse(scan->tmp))) 295 goto bad; 296 sfsprintf(scan->nam, sizeof(scan->nam), "%s", s); 297 } 298 else 299 sfsprintf(scan->nam, sizeof(scan->nam), "%s%s%s.%s", info->prefix, name, info->suffix, version); 300 if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION)) 301 { 302 if (scan->flags & DLL_INFO_PREVER) 303 { 304 if (!version) 305 version = "*([0-9_])"; 306 else 307 { 308 t = buf; 309 for (s = (char*)version; *s; s++) 310 if (isdigit(*s) && t < &buf[sizeof(buf)-1]) 311 *t++ = *s; 312 *t = 0; 313 version = (const char*)buf; 314 } 315 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s%s%s", info->prefix, name, version, info->suffix); 316 } 317 else if (version) 318 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(%s([-.])%s%s|%s.%s)", info->prefix, name, strchr(version, '.') ? "@" : "?", version, info->suffix, info->suffix, version); 319 else 320 { 321 version = "*([0-9.])"; 322 sfsprintf(scan->pat, sizeof(scan->pat), "%s%s@(?([-.])%s%s|%s%s)", info->prefix, name, version, info->suffix, info->suffix, version); 323 } 324 } 325 scan->sp = scan->sb = (scan->lib ? scan->lib : info->sibling); 326 scan->prelen = strlen(info->prefix); 327 scan->suflen = strlen(info->suffix); 328 return scan; 329 bad: 330 dllsclose(scan); 331 return 0; 332 } 333 334 /* 335 * close a scan stream 336 */ 337 338 int 339 dllsclose(Dllscan_t* scan) 340 { 341 if (!scan) 342 return -1; 343 if (scan->fts) 344 fts_close(scan->fts); 345 if (scan->dict) 346 dtclose(scan->dict); 347 if (scan->tmp) 348 sfclose(scan->tmp); 349 if (scan->vm) 350 vmclose(scan->vm); 351 return 0; 352 } 353 354 /* 355 * return the next scan stream entry 356 */ 357 358 Dllent_t* 359 dllsread(register Dllscan_t* scan) 360 { 361 register char* p; 362 register char* b; 363 register char* t; 364 register Uniq_t* u; 365 register int n; 366 register int m; 367 368 if (scan->flags & DLL_MATCH_DONE) 369 return 0; 370 again: 371 do 372 { 373 while (!scan->ent || !(scan->ent = scan->ent->fts_link)) 374 { 375 if (scan->fts) 376 { 377 fts_close(scan->fts); 378 scan->fts = 0; 379 } 380 if (!scan->pb) 381 scan->pb = pathbin(); 382 else if (!*scan->sp) 383 { 384 scan->sp = scan->sb; 385 if (!*scan->pe++) 386 return 0; 387 scan->pb = scan->pe; 388 } 389 for (p = scan->pp = scan->pb; *p && *p != ':'; p++) 390 if (*p == '/') 391 scan->pp = p; 392 scan->pe = p; 393 if (*scan->sp == bin) 394 scan->off = sfprintf(scan->tmp, "%-.*s", scan->pe - scan->pb, scan->pb); 395 else 396 scan->off = sfprintf(scan->tmp, "%-.*s/%s", scan->pp - scan->pb, scan->pb, *scan->sp); 397 scan->sp++; 398 if (!(scan->flags & DLL_MATCH_NAME)) 399 { 400 sfprintf(scan->tmp, "/%s", scan->nam); 401 if (!(p = sfstruse(scan->tmp))) 402 return 0; 403 if (!eaccess(p, R_OK)) 404 { 405 b = scan->nam; 406 goto found; 407 } 408 if (errno != ENOENT) 409 continue; 410 } 411 if (scan->flags & (DLL_MATCH_NAME|DLL_MATCH_VERSION)) 412 { 413 sfstrseek(scan->tmp, scan->off, SEEK_SET); 414 if (!(t = sfstruse(scan->tmp))) 415 return 0; 416 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))) 417 break; 418 } 419 } 420 } while (!strmatch(scan->ent->fts_name, scan->pat)); 421 b = scan->ent->fts_name; 422 sfstrseek(scan->tmp, scan->off, SEEK_SET); 423 sfprintf(scan->tmp, "/%s", b); 424 if (!(p = sfstruse(scan->tmp))) 425 return 0; 426 found: 427 b = scan->buf + sfsprintf(scan->buf, sizeof(scan->buf), "%s", b + scan->prelen); 428 if (!(scan->flags & DLL_INFO_PREVER)) 429 while (b > scan->buf) 430 { 431 if (!isdigit(*(b - 1)) && *(b - 1) != '.') 432 break; 433 b--; 434 } 435 b -= scan->suflen; 436 if (b > (scan->buf + 2) && (*(b - 1) == 'g' || *(b - 1) == 'O') && *(b - 2) == '-') 437 b -= 2; 438 n = m = 0; 439 for (t = b; t > scan->buf; t--) 440 if (isdigit(*(t - 1))) 441 n = 1; 442 else if (*(t - 1) != m) 443 { 444 if (*(t - 1) == '.' || *(t - 1) == '-' || *(t - 1) == '_') 445 { 446 n = 1; 447 if (m) 448 { 449 m = -1; 450 t--; 451 break; 452 } 453 m = *(t - 1); 454 } 455 else 456 break; 457 } 458 if (n) 459 { 460 if (isdigit(t[0]) && isdigit(t[1]) && !isdigit(t[2])) 461 n = (t[0] - '0') * 10 + (t[1] - '0'); 462 else if (isdigit(t[1]) && isdigit(t[2]) && !isdigit(t[3])) 463 n = (t[1] - '0') * 10 + (t[2] - '0'); 464 else 465 n = 0; 466 if (n && !(n & (n - 1))) 467 { 468 if (!isdigit(t[0])) 469 t++; 470 m = *(t += 2); 471 } 472 if (m || (scan->flags & DLL_INFO_PREVER)) 473 b = t; 474 } 475 *b = 0; 476 if (!*(b = scan->buf)) 477 goto again; 478 if (scan->uniq) 479 { 480 if (!scan->dict) 481 { 482 scan->disc.key = offsetof(Uniq_t, name); 483 scan->disc.size = 0; 484 scan->disc.link = offsetof(Uniq_t, link); 485 if (!(scan->dict = dtopen(&scan->disc, Dthash))) 486 return 0; 487 dtinsert(scan->dict, scan->uniq); 488 } 489 if (dtmatch(scan->dict, b)) 490 goto again; 491 if (!(u = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b)))) 492 return 0; 493 strcpy(u->name, b); 494 dtinsert(scan->dict, u); 495 } 496 else if (!(scan->flags & DLL_MATCH_NAME)) 497 scan->flags |= DLL_MATCH_DONE; 498 else if (!(scan->uniq = vmnewof(scan->vm, 0, Uniq_t, 1, strlen(b)))) 499 return 0; 500 else 501 strcpy(scan->uniq->name, b); 502 scan->entry.name = b; 503 scan->entry.path = p; 504 return &scan->entry; 505 } 506