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