1/* $NetBSD$ */ 2 3/* 4** Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp 5** Dynamic library loader for Lua 6** See Copyright Notice in lua.h 7** 8** This module contains an implementation of loadlib for Unix systems 9** that have dlfcn, an implementation for Darwin (Mac OS X), an 10** implementation for Windows, and a stub for other systems. 11*/ 12 13 14#include <stdlib.h> 15#include <string.h> 16 17 18#define loadlib_c 19#define LUA_LIB 20 21#include "lua.h" 22 23#include "lauxlib.h" 24#include "lualib.h" 25 26 27/* prefix for open functions in C libraries */ 28#define LUA_POF "luaopen_" 29 30/* separator for open functions in C libraries */ 31#define LUA_OFSEP "_" 32 33 34#define LIBPREFIX "LOADLIB: " 35 36#define POF LUA_POF 37#define LIB_FAIL "open" 38 39 40/* error codes for ll_loadfunc */ 41#define ERRLIB 1 42#define ERRFUNC 2 43 44#define setprogdir(L) ((void)0) 45 46 47static void ll_unloadlib (void *lib); 48static void *ll_load (lua_State *L, const char *path); 49static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); 50 51 52 53#if defined(LUA_DL_DLOPEN) 54/* 55** {======================================================================== 56** This is an implementation of loadlib based on the dlfcn interface. 57** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, 58** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least 59** as an emulation layer on top of native functions. 60** ========================================================================= 61*/ 62 63#include <dlfcn.h> 64 65static void ll_unloadlib (void *lib) { 66 dlclose(lib); 67} 68 69 70static void *ll_load (lua_State *L, const char *path) { 71 void *lib = dlopen(path, RTLD_NOW); 72 if (lib == NULL) lua_pushstring(L, dlerror()); 73 return lib; 74} 75 76 77static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { 78 lua_CFunction f = (lua_CFunction)dlsym(lib, sym); 79 if (f == NULL) lua_pushstring(L, dlerror()); 80 return f; 81} 82 83/* }====================================================== */ 84 85 86 87#elif defined(LUA_DL_DLL) 88/* 89** {====================================================================== 90** This is an implementation of loadlib for Windows using native functions. 91** ======================================================================= 92*/ 93 94#include <windows.h> 95 96 97#undef setprogdir 98 99static void setprogdir (lua_State *L) { 100 char buff[MAX_PATH + 1]; 101 char *lb; 102 DWORD nsize = sizeof(buff)/sizeof(char); 103 DWORD n = GetModuleFileNameA(NULL, buff, nsize); 104 if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) 105 luaL_error(L, "unable to get ModuleFileName"); 106 else { 107 *lb = '\0'; 108 luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); 109 lua_remove(L, -2); /* remove original string */ 110 } 111} 112 113 114static void pusherror (lua_State *L) { 115 int error = GetLastError(); 116 char buffer[128]; 117 if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 118 NULL, error, 0, buffer, sizeof(buffer), NULL)) 119 lua_pushstring(L, buffer); 120 else 121 lua_pushfstring(L, "system error %d\n", error); 122} 123 124static void ll_unloadlib (void *lib) { 125 FreeLibrary((HINSTANCE)lib); 126} 127 128 129static void *ll_load (lua_State *L, const char *path) { 130 HINSTANCE lib = LoadLibraryA(path); 131 if (lib == NULL) pusherror(L); 132 return lib; 133} 134 135 136static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { 137 lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); 138 if (f == NULL) pusherror(L); 139 return f; 140} 141 142/* }====================================================== */ 143 144 145 146#elif defined(LUA_DL_DYLD) 147/* 148** {====================================================================== 149** Native Mac OS X / Darwin Implementation 150** ======================================================================= 151*/ 152 153#include <mach-o/dyld.h> 154 155 156/* Mac appends a `_' before C function names */ 157#undef POF 158#define POF "_" LUA_POF 159 160 161static void pusherror (lua_State *L) { 162 const char *err_str; 163 const char *err_file; 164 NSLinkEditErrors err; 165 int err_num; 166 NSLinkEditError(&err, &err_num, &err_file, &err_str); 167 lua_pushstring(L, err_str); 168} 169 170 171static const char *errorfromcode (NSObjectFileImageReturnCode ret) { 172 switch (ret) { 173 case NSObjectFileImageInappropriateFile: 174 return "file is not a bundle"; 175 case NSObjectFileImageArch: 176 return "library is for wrong CPU type"; 177 case NSObjectFileImageFormat: 178 return "bad format"; 179 case NSObjectFileImageAccess: 180 return "cannot access file"; 181 case NSObjectFileImageFailure: 182 default: 183 return "unable to load library"; 184 } 185} 186 187 188static void ll_unloadlib (void *lib) { 189 NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); 190} 191 192 193static void *ll_load (lua_State *L, const char *path) { 194 NSObjectFileImage img; 195 NSObjectFileImageReturnCode ret; 196 /* this would be a rare case, but prevents crashing if it happens */ 197 if(!_dyld_present()) { 198 lua_pushliteral(L, "dyld not present"); 199 return NULL; 200 } 201 ret = NSCreateObjectFileImageFromFile(path, &img); 202 if (ret == NSObjectFileImageSuccess) { 203 NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | 204 NSLINKMODULE_OPTION_RETURN_ON_ERROR); 205 NSDestroyObjectFileImage(img); 206 if (mod == NULL) pusherror(L); 207 return mod; 208 } 209 lua_pushstring(L, errorfromcode(ret)); 210 return NULL; 211} 212 213 214static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { 215 NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); 216 if (nss == NULL) { 217 lua_pushfstring(L, "symbol " LUA_QS " not found", sym); 218 return NULL; 219 } 220 return (lua_CFunction)NSAddressOfSymbol(nss); 221} 222 223/* }====================================================== */ 224 225 226 227#else 228/* 229** {====================================================== 230** Fallback for other systems 231** ======================================================= 232*/ 233 234#undef LIB_FAIL 235#define LIB_FAIL "absent" 236 237 238#define DLMSG "dynamic libraries not enabled; check your Lua installation" 239 240 241static void ll_unloadlib (void *lib) { 242 (void)lib; /* to avoid warnings */ 243} 244 245 246static void *ll_load (lua_State *L, const char *path) { 247 (void)path; /* to avoid warnings */ 248 lua_pushliteral(L, DLMSG); 249 return NULL; 250} 251 252 253static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { 254 (void)lib; (void)sym; /* to avoid warnings */ 255 lua_pushliteral(L, DLMSG); 256 return NULL; 257} 258 259/* }====================================================== */ 260#endif 261 262 263 264static void **ll_register (lua_State *L, const char *path) { 265 void **plib; 266 lua_pushfstring(L, "%s%s", LIBPREFIX, path); 267 lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ 268 if (!lua_isnil(L, -1)) /* is there an entry? */ 269 plib = (void **)lua_touserdata(L, -1); 270 else { /* no entry yet; create one */ 271 lua_pop(L, 1); 272 plib = (void **)lua_newuserdata(L, sizeof(const void *)); 273 *plib = NULL; 274 luaL_getmetatable(L, "_LOADLIB"); 275 lua_setmetatable(L, -2); 276 lua_pushfstring(L, "%s%s", LIBPREFIX, path); 277 lua_pushvalue(L, -2); 278 lua_settable(L, LUA_REGISTRYINDEX); 279 } 280 return plib; 281} 282 283 284/* 285** __gc tag method: calls library's `ll_unloadlib' function with the lib 286** handle 287*/ 288static int gctm (lua_State *L) { 289 void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); 290 if (*lib) ll_unloadlib(*lib); 291 *lib = NULL; /* mark library as closed */ 292 return 0; 293} 294 295 296static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { 297 void **reg = ll_register(L, path); 298 if (*reg == NULL) *reg = ll_load(L, path); 299 if (*reg == NULL) 300 return ERRLIB; /* unable to load library */ 301 else { 302 lua_CFunction f = ll_sym(L, *reg, sym); 303 if (f == NULL) 304 return ERRFUNC; /* unable to find function */ 305 lua_pushcfunction(L, f); 306 return 0; /* return function */ 307 } 308} 309 310 311static int ll_loadlib (lua_State *L) { 312 const char *path = luaL_checkstring(L, 1); 313 const char *init = luaL_checkstring(L, 2); 314 int stat = ll_loadfunc(L, path, init); 315 if (stat == 0) /* no errors? */ 316 return 1; /* return the loaded function */ 317 else { /* error; error message is on stack top */ 318 lua_pushnil(L); 319 lua_insert(L, -2); 320 lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); 321 return 3; /* return nil, error message, and where */ 322 } 323} 324 325 326 327/* 328** {====================================================== 329** 'require' function 330** ======================================================= 331*/ 332 333 334static int readable (const char *filename) { 335 FILE *f = fopen(filename, "r"); /* try to open file */ 336 if (f == NULL) return 0; /* open failed */ 337 fclose(f); 338 return 1; 339} 340 341 342static const char *pushnexttemplate (lua_State *L, const char *path) { 343 const char *l; 344 while (*path == *LUA_PATHSEP) path++; /* skip separators */ 345 if (*path == '\0') return NULL; /* no more templates */ 346 l = strchr(path, *LUA_PATHSEP); /* find next separator */ 347 if (l == NULL) l = path + strlen(path); 348 lua_pushlstring(L, path, l - path); /* template */ 349 return l; 350} 351 352 353static const char *findfile (lua_State *L, const char *name, 354 const char *pname) { 355 const char *path; 356 name = luaL_gsub(L, name, ".", LUA_DIRSEP); 357 lua_getfield(L, LUA_ENVIRONINDEX, pname); 358 path = lua_tostring(L, -1); 359 if (path == NULL) 360 luaL_error(L, LUA_QL("package.%s") " must be a string", pname); 361 lua_pushliteral(L, ""); /* error accumulator */ 362 while ((path = pushnexttemplate(L, path)) != NULL) { 363 const char *filename; 364 filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); 365 lua_remove(L, -2); /* remove path template */ 366 if (readable(filename)) /* does file exist and is readable? */ 367 return filename; /* return that file name */ 368 lua_pushfstring(L, "\n\tno file " LUA_QS, filename); 369 lua_remove(L, -2); /* remove file name */ 370 lua_concat(L, 2); /* add entry to possible error message */ 371 } 372 return NULL; /* not found */ 373} 374 375 376static void loaderror (lua_State *L, const char *filename) { 377 luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", 378 lua_tostring(L, 1), filename, lua_tostring(L, -1)); 379} 380 381 382static int loader_Lua (lua_State *L) { 383 const char *filename; 384 const char *name = luaL_checkstring(L, 1); 385 filename = findfile(L, name, "path"); 386 if (filename == NULL) return 1; /* library not found in this path */ 387 if (luaL_loadfile(L, filename) != 0) 388 loaderror(L, filename); 389 return 1; /* library loaded successfully */ 390} 391 392 393static const char *mkfuncname (lua_State *L, const char *modname) { 394 const char *funcname; 395 const char *mark = strchr(modname, *LUA_IGMARK); 396 if (mark) modname = mark + 1; 397 funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); 398 funcname = lua_pushfstring(L, POF"%s", funcname); 399 lua_remove(L, -2); /* remove 'gsub' result */ 400 return funcname; 401} 402 403 404static int loader_C (lua_State *L) { 405 const char *funcname; 406 const char *name = luaL_checkstring(L, 1); 407 const char *filename = findfile(L, name, "cpath"); 408 if (filename == NULL) return 1; /* library not found in this path */ 409 funcname = mkfuncname(L, name); 410 if (ll_loadfunc(L, filename, funcname) != 0) 411 loaderror(L, filename); 412 return 1; /* library loaded successfully */ 413} 414 415 416static int loader_Croot (lua_State *L) { 417 const char *funcname; 418 const char *filename; 419 const char *name = luaL_checkstring(L, 1); 420 const char *p = strchr(name, '.'); 421 int stat; 422 if (p == NULL) return 0; /* is root */ 423 lua_pushlstring(L, name, p - name); 424 filename = findfile(L, lua_tostring(L, -1), "cpath"); 425 if (filename == NULL) return 1; /* root not found */ 426 funcname = mkfuncname(L, name); 427 if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { 428 if (stat != ERRFUNC) loaderror(L, filename); /* real error */ 429 lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, 430 name, filename); 431 return 1; /* function not found */ 432 } 433 return 1; 434} 435 436 437static int loader_preload (lua_State *L) { 438 const char *name = luaL_checkstring(L, 1); 439 lua_getfield(L, LUA_ENVIRONINDEX, "preload"); 440 if (!lua_istable(L, -1)) 441 luaL_error(L, LUA_QL("package.preload") " must be a table"); 442 lua_getfield(L, -1, name); 443 if (lua_isnil(L, -1)) /* not found? */ 444 lua_pushfstring(L, "\n\tno field package.preload['%s']", name); 445 return 1; 446} 447 448 449static const int sentinel_ = 0; 450#define sentinel ((void *)&sentinel_) 451 452 453static int ll_require (lua_State *L) { 454 const char *name = luaL_checkstring(L, 1); 455 int i; 456 lua_settop(L, 1); /* _LOADED table will be at index 2 */ 457 lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); 458 lua_getfield(L, 2, name); 459 if (lua_toboolean(L, -1)) { /* is it there? */ 460 if (lua_touserdata(L, -1) == sentinel) /* check loops */ 461 luaL_error(L, "loop or previous error loading module " LUA_QS, name); 462 return 1; /* package is already loaded */ 463 } 464 /* else must load it; iterate over available loaders */ 465 lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); 466 if (!lua_istable(L, -1)) 467 luaL_error(L, LUA_QL("package.loaders") " must be a table"); 468 lua_pushliteral(L, ""); /* error message accumulator */ 469 for (i=1; ; i++) { 470 lua_rawgeti(L, -2, i); /* get a loader */ 471 if (lua_isnil(L, -1)) 472 luaL_error(L, "module " LUA_QS " not found:%s", 473 name, lua_tostring(L, -2)); 474 lua_pushstring(L, name); 475 lua_call(L, 1, 1); /* call it */ 476 if (lua_isfunction(L, -1)) /* did it find module? */ 477 break; /* module loaded successfully */ 478 else if (lua_isstring(L, -1)) /* loader returned error message? */ 479 lua_concat(L, 2); /* accumulate it */ 480 else 481 lua_pop(L, 1); 482 } 483 lua_pushlightuserdata(L, sentinel); 484 lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ 485 lua_pushstring(L, name); /* pass name as argument to module */ 486 lua_call(L, 1, 1); /* run loaded module */ 487 if (!lua_isnil(L, -1)) /* non-nil return? */ 488 lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ 489 lua_getfield(L, 2, name); 490 if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ 491 lua_pushboolean(L, 1); /* use true as result */ 492 lua_pushvalue(L, -1); /* extra copy to be returned */ 493 lua_setfield(L, 2, name); /* _LOADED[name] = true */ 494 } 495 return 1; 496} 497 498/* }====================================================== */ 499 500 501 502/* 503** {====================================================== 504** 'module' function 505** ======================================================= 506*/ 507 508 509static void setfenv (lua_State *L) { 510 lua_Debug ar; 511 if (lua_getstack(L, 1, &ar) == 0 || 512 lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ 513 lua_iscfunction(L, -1)) 514 luaL_error(L, LUA_QL("module") " not called from a Lua function"); 515 lua_pushvalue(L, -2); 516 lua_setfenv(L, -2); 517 lua_pop(L, 1); 518} 519 520 521static void dooptions (lua_State *L, int n) { 522 int i; 523 for (i = 2; i <= n; i++) { 524 lua_pushvalue(L, i); /* get option (a function) */ 525 lua_pushvalue(L, -2); /* module */ 526 lua_call(L, 1, 0); 527 } 528} 529 530 531static void modinit (lua_State *L, const char *modname) { 532 const char *dot; 533 lua_pushvalue(L, -1); 534 lua_setfield(L, -2, "_M"); /* module._M = module */ 535 lua_pushstring(L, modname); 536 lua_setfield(L, -2, "_NAME"); 537 dot = strrchr(modname, '.'); /* look for last dot in module name */ 538 if (dot == NULL) dot = modname; 539 else dot++; 540 /* set _PACKAGE as package name (full module name minus last part) */ 541 lua_pushlstring(L, modname, dot - modname); 542 lua_setfield(L, -2, "_PACKAGE"); 543} 544 545 546static int ll_module (lua_State *L) { 547 const char *modname = luaL_checkstring(L, 1); 548 int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ 549 lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); 550 lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ 551 if (!lua_istable(L, -1)) { /* not found? */ 552 lua_pop(L, 1); /* remove previous result */ 553 /* try global variable (and create one if it does not exist) */ 554 if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) 555 return luaL_error(L, "name conflict for module " LUA_QS, modname); 556 lua_pushvalue(L, -1); 557 lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ 558 } 559 /* check whether table already has a _NAME field */ 560 lua_getfield(L, -1, "_NAME"); 561 if (!lua_isnil(L, -1)) /* is table an initialized module? */ 562 lua_pop(L, 1); 563 else { /* no; initialize it */ 564 lua_pop(L, 1); 565 modinit(L, modname); 566 } 567 lua_pushvalue(L, -1); 568 setfenv(L); 569 dooptions(L, loaded - 1); 570 return 0; 571} 572 573 574static int ll_seeall (lua_State *L) { 575 luaL_checktype(L, 1, LUA_TTABLE); 576 if (!lua_getmetatable(L, 1)) { 577 lua_createtable(L, 0, 1); /* create new metatable */ 578 lua_pushvalue(L, -1); 579 lua_setmetatable(L, 1); 580 } 581 lua_pushvalue(L, LUA_GLOBALSINDEX); 582 lua_setfield(L, -2, "__index"); /* mt.__index = _G */ 583 return 0; 584} 585 586 587/* }====================================================== */ 588 589 590 591/* auxiliary mark (for internal use) */ 592#define AUXMARK "\1" 593 594static void setpath (lua_State *L, const char *fieldname, const char *envname, 595 const char *def) { 596 const char *path = getenv(envname); 597 if (path == NULL) /* no environment variable? */ 598 lua_pushstring(L, def); /* use default */ 599 else { 600 /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ 601 path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, 602 LUA_PATHSEP AUXMARK LUA_PATHSEP); 603 luaL_gsub(L, path, AUXMARK, def); 604 lua_remove(L, -2); 605 } 606 setprogdir(L); 607 lua_setfield(L, -2, fieldname); 608} 609 610 611static const luaL_Reg pk_funcs[] = { 612 {"loadlib", ll_loadlib}, 613 {"seeall", ll_seeall}, 614 {NULL, NULL} 615}; 616 617 618static const luaL_Reg ll_funcs[] = { 619 {"module", ll_module}, 620 {"require", ll_require}, 621 {NULL, NULL} 622}; 623 624 625static const lua_CFunction loaders[] = 626 {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; 627 628 629LUALIB_API int luaopen_package (lua_State *L) { 630 int i; 631 /* create new type _LOADLIB */ 632 luaL_newmetatable(L, "_LOADLIB"); 633 lua_pushcfunction(L, gctm); 634 lua_setfield(L, -2, "__gc"); 635 /* create `package' table */ 636 luaL_register(L, LUA_LOADLIBNAME, pk_funcs); 637#if defined(LUA_COMPAT_LOADLIB) 638 lua_getfield(L, -1, "loadlib"); 639 lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); 640#endif 641 lua_pushvalue(L, -1); 642 lua_replace(L, LUA_ENVIRONINDEX); 643 /* create `loaders' table */ 644 lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); 645 /* fill it with pre-defined loaders */ 646 for (i=0; loaders[i] != NULL; i++) { 647 lua_pushcfunction(L, loaders[i]); 648 lua_rawseti(L, -2, i+1); 649 } 650 lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ 651 setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ 652 setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ 653 /* store config information */ 654 lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" 655 LUA_EXECDIR "\n" LUA_IGMARK); 656 lua_setfield(L, -2, "config"); 657 /* set field `loaded' */ 658 luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); 659 lua_setfield(L, -2, "loaded"); 660 /* set field `preload' */ 661 lua_newtable(L); 662 lua_setfield(L, -2, "preload"); 663 lua_pushvalue(L, LUA_GLOBALSINDEX); 664 luaL_register(L, NULL, ll_funcs); /* open lib into global table */ 665 lua_pop(L, 1); 666 return 1; /* return 'package' table */ 667} 668 669