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