rpm 5.3.7
|
00001 /*@-moduncon -mustmod -realcompare -sizeoftype @*/ 00002 #include "system.h" 00003 00004 #ifdef WITH_LUA 00005 #define _RPMIOB_INTERNAL 00006 #include <rpmiotypes.h> 00007 #include <rpmio.h> 00008 #include <rpmmacro.h> 00009 #include <rpmlog.h> 00010 #include <rpmurl.h> 00011 #include <rpmhook.h> 00012 #include <rpmcb.h> 00013 #include <argv.h> 00014 #include <popt.h> /* XXX poptSaneFile test */ 00015 00016 #include <lua.h> 00017 #include <lualib.h> 00018 #include <lauxlib.h> 00019 #ifdef WITH_SYCK 00020 LUALIB_API int luaopen_syck(lua_State *L) 00021 /*@modifies L @*/; 00022 #endif /* WITH_SYCK */ 00023 #ifdef WITH_LUA_INTERNAL 00024 #include <llocal.h> 00025 #include <lposix.h> 00026 #include <lrexlib.h> 00027 #include <luuid.h> 00028 #include <lwrs.h> 00029 #ifdef USE_LUA_CRYPTO /* XXX external lua modules instead. */ 00030 #include <lcrypto.h> 00031 #include <lxplib.h> 00032 #endif 00033 #ifdef USE_LUA_SOCKET /* XXX external lua modules instead. */ 00034 #include <luasocket.h> 00035 #endif 00036 #endif 00037 00038 #include <unistd.h> 00039 #include <assert.h> 00040 00041 #define _RPMLUA_INTERNAL 00042 #include "rpmlua.h" 00043 00044 #include "debug.h" 00045 00046 /*@access rpmiob @*/ 00047 00048 #else /* WITH_LUA */ 00049 #include <rpmio.h> 00050 #endif 00051 00052 /*@unchecked@*/ 00053 int _rpmlua_debug = 0; 00054 00055 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00056 rpmioPool _rpmluaPool = NULL; 00057 00058 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00059 rpmioPool _rpmluavPool = NULL; 00060 00061 #ifdef WITH_LUA 00062 00063 #if !defined(HAVE_VSNPRINTF) 00064 static inline int vsnprintf(char * buf, /*@unused@*/ size_t nb, 00065 const char * fmt, va_list ap) 00066 { 00067 return vsprintf(buf, fmt, ap); 00068 } 00069 #endif 00070 00071 #define INITSTATE(_lua, lua) \ 00072 rpmlua lua = _lua ? _lua : \ 00073 (globalLuaState ? globalLuaState : \ 00074 /*@-mods@*/ \ 00075 (globalLuaState = rpmluaNew()) \ 00076 /*@=mods@*/ \ 00077 ) 00078 00079 /*@only@*/ /*@unchecked@*/ /*@relnull@*/ 00080 static rpmlua globalLuaState; 00081 00082 static int luaopen_rpm(lua_State *L) 00083 /*@modifies L @*/; 00084 static int rpm_print(lua_State *L) 00085 /*@globals fileSystem @*/ 00086 /*@modifies L, fileSystem @*/; 00087 00088 /*@unchecked@*/ /*@observer@*/ 00089 const char * rpmluaFiles = RPMLUAFILES; 00090 00091 /*@unchecked@*/ /*@observer@*/ 00092 const char * rpmluaPath = "%{?_rpmhome}%{!?_rpmhome:" USRLIBRPM "}/lua/?.lua"; 00093 00094 rpmlua rpmluaGetGlobalState(void) 00095 { 00096 /*@-globstate@*/ 00097 return globalLuaState; 00098 /*@=globstate@*/ 00099 } 00100 00101 static void rpmluaFini(void * _lua) 00102 /*@globals globalLuaState @*/ 00103 /*@modifies globalLuaState @*/ 00104 { 00105 rpmlua lua = _lua; 00106 00107 if (lua->L) lua_close(lua->L); 00108 lua->L = NULL; 00109 lua->printbuf = _free(lua->printbuf); 00110 } 00111 00112 static rpmlua rpmluaGetPool(/*@null@*/ rpmioPool pool) 00113 /*@globals _rpmluaPool, fileSystem @*/ 00114 /*@modifies pool, _rpmluaPool, fileSystem @*/ 00115 { 00116 rpmlua lua; 00117 00118 if (_rpmluaPool == NULL) { 00119 _rpmluaPool = rpmioNewPool("lua", sizeof(*lua), -1, _rpmlua_debug, 00120 NULL, NULL, rpmluaFini); 00121 pool = _rpmluaPool; 00122 } 00123 return (rpmlua) rpmioGetPool(pool, sizeof(*lua)); 00124 } 00125 00126 void *rpmluaFree(rpmlua lua) 00127 { 00128 if (lua == NULL) lua = globalLuaState; 00129 (void)rpmioFreePoolItem((rpmioItem)lua, __FUNCTION__, __FILE__, __LINE__); 00130 if (lua == globalLuaState) globalLuaState = NULL; 00131 return NULL; 00132 } 00133 00134 /*@-globs -mods@*/ /* XXX hide rpmGlobalMacroContext mods for now. */ 00135 rpmlua rpmluaNew(void) 00136 { 00137 rpmlua lua = rpmluaGetPool(_rpmluaPool); 00138 lua_State *L = lua_open(); 00139 /*@-readonlytrans -nullassign @*/ 00140 /*@observer@*/ /*@unchecked@*/ 00141 static const luaL_reg lualibs[] = { 00142 /* standard LUA libraries */ 00143 {"", luaopen_base}, 00144 {LUA_LOADLIBNAME, luaopen_package}, 00145 {LUA_TABLIBNAME, luaopen_table}, 00146 {LUA_IOLIBNAME, luaopen_io}, 00147 {LUA_OSLIBNAME, luaopen_os}, 00148 {LUA_STRLIBNAME, luaopen_string}, 00149 {LUA_MATHLIBNAME, luaopen_math}, 00150 {LUA_DBLIBNAME, luaopen_debug}, 00151 #ifdef WITH_SYCK 00152 {"lsyck", luaopen_syck}, 00153 #endif /* WITH_SYCK */ 00154 /* local LUA libraries (RPM only) */ 00155 #ifdef WITH_LUA_INTERNAL 00156 {"posix", luaopen_posix}, 00157 {"rex_posix", luaopen_rex_posix}, 00158 {"rex_pcre", luaopen_rex_pcre}, 00159 {"uuid", luaopen_uuid}, 00160 {"wrs", luaopen_wrs}, 00161 #ifdef USE_LUA_CRYPTO /* XXX external lua modules instead. */ 00162 {"crypto", luaopen_crypto}, 00163 {"lxp", luaopen_lxp}, 00164 #endif 00165 #ifdef USE_LUA_SOCKET /* XXX external lua modules instead. */ 00166 {"socket", luaopen_socket_core}, 00167 #endif 00168 {"local", luaopen_local}, 00169 #endif 00170 {"rpm", luaopen_rpm}, 00171 {NULL, NULL}, 00172 }; 00173 /*@=readonlytrans =nullassign @*/ 00174 /*@observer@*/ /*@unchecked@*/ 00175 const luaL_reg *lib = lualibs; 00176 char *path_buf; 00177 char *path_next; 00178 char *path; 00179 00180 lua->L = L; 00181 lua->pushsize = 0; 00182 lua->storeprint = 0; 00183 /* XXX TODO: use an rpmiob here. */ 00184 lua->printbufsize = 0; 00185 lua->printbufused = 0; 00186 lua->printbuf = NULL; 00187 00188 for (; lib->name; lib++) { 00189 /*@-noeffectuncon@*/ 00190 lua_pushcfunction(L, lib->func); 00191 lua_pushstring(L, lib->name); 00192 lua_call(L, 1, 0); 00193 /*@=noeffectuncon@*/ 00194 } 00195 { const char * _lua_path = rpmGetPath(rpmluaPath, NULL); 00196 if (_lua_path != NULL) { 00197 lua_pushliteral(L, "LUA_PATH"); 00198 lua_pushstring(L, _lua_path); 00199 _lua_path = _free(_lua_path); 00200 } 00201 } 00202 lua_rawset(L, LUA_GLOBALSINDEX); 00203 lua_pushliteral(L, "print"); 00204 lua_pushcfunction(L, rpm_print); 00205 lua_rawset(L, LUA_GLOBALSINDEX); 00206 rpmluaSetData(lua, "lua", lua); 00207 00208 /* load all standard RPM Lua script files */ 00209 path_buf = xstrdup(rpmluaFiles); 00210 for (path = path_buf; path != NULL && *path != '\0'; path = path_next) { 00211 const char **av; 00212 struct stat st; 00213 int ac, i; 00214 00215 /* locate start of next path element */ 00216 path_next = strchr(path, ':'); 00217 if (path_next != NULL && *path_next == ':') 00218 *path_next++ = '\0'; 00219 else 00220 path_next = path + strlen(path); 00221 00222 /* glob-expand the path element */ 00223 ac = 0; 00224 av = NULL; 00225 if ((i = rpmGlob(path, &ac, &av)) != 0) 00226 continue; 00227 00228 /* work-off each resulting file from the path element */ 00229 for (i = 0; i < ac; i++) { 00230 const char *fn = av[i]; 00231 if (fn[0] == '@' /* attention */) { 00232 fn++; 00233 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \ 00234 !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */ 00235 if (!rpmSecuritySaneFile(fn)) 00236 #else 00237 if (!poptSaneFile(fn)) 00238 #endif 00239 { 00240 rpmlog(RPMLOG_WARNING, "existing RPM Lua script file \"%s\" considered INSECURE -- not loaded\n", fn); 00241 /*@innercontinue@*/ continue; 00242 } 00243 } 00244 if (Stat(fn, &st) != -1) 00245 (void)rpmluaRunScriptFile(lua, fn); 00246 av[i] = _free(av[i]); 00247 } 00248 av = _free(av); 00249 } 00250 path_buf = _free(path_buf); 00251 00252 return ((rpmlua)rpmioLinkPoolItem((rpmioItem)lua, __FUNCTION__, __FILE__, __LINE__)); 00253 } 00254 /*@=globs =mods@*/ 00255 00256 void rpmluaSetData(rpmlua _lua, const char *key, const void *data) 00257 { 00258 INITSTATE(_lua, lua); 00259 lua_State *L = lua->L; 00260 lua_pushliteral(L, "rpm_"); 00261 lua_pushstring(L, key); 00262 lua_concat(L, 2); 00263 if (data == NULL) 00264 lua_pushnil(L); 00265 else 00266 lua_pushlightuserdata(L, (void *)data); 00267 lua_rawset(L, LUA_REGISTRYINDEX); 00268 } 00269 00270 /*@null@*/ 00271 static void *getdata(lua_State *L, const char *key) 00272 /*@modifies L @*/ 00273 { 00274 void *ret = NULL; 00275 lua_pushliteral(L, "rpm_"); 00276 lua_pushstring(L, key); 00277 lua_concat(L, 2); 00278 lua_rawget(L, LUA_REGISTRYINDEX); 00279 if (lua_islightuserdata(L, -1)) 00280 ret = lua_touserdata(L, -1); 00281 lua_pop(L, 1); 00282 return ret; 00283 } 00284 00285 void *rpmluaGetData(rpmlua _lua, const char *key) 00286 { 00287 INITSTATE(_lua, lua); 00288 return getdata(lua->L, key); 00289 } 00290 00291 void rpmluaSetPrintBuffer(rpmlua _lua, int flag) 00292 { 00293 INITSTATE(_lua, lua); 00294 lua->storeprint = flag; 00295 lua->printbuf = _free(lua->printbuf); 00296 lua->printbufsize = 0; 00297 lua->printbufused = 0; 00298 } 00299 00300 const char *rpmluaGetPrintBuffer(rpmlua _lua) 00301 { 00302 INITSTATE(_lua, lua); 00303 return lua->printbuf; 00304 } 00305 00306 static int pushvar(lua_State *L, rpmluavType type, void *value) 00307 /*@modifies L @*/ 00308 { 00309 int ret = 0; 00310 switch (type) { 00311 case RPMLUAV_NIL: 00312 lua_pushnil(L); 00313 break; 00314 case RPMLUAV_STRING: 00315 lua_pushstring(L, *((char **)value)); 00316 break; 00317 case RPMLUAV_NUMBER: 00318 lua_pushnumber(L, *((double *)value)); 00319 break; 00320 default: 00321 ret = -1; 00322 break; 00323 } 00324 return ret; 00325 } 00326 00327 void rpmluaSetVar(rpmlua _lua, rpmluav var) 00328 { 00329 INITSTATE(_lua, lua); 00330 lua_State *L = lua->L; 00331 if (var->listmode && lua->pushsize > 0) { 00332 if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) { 00333 var->keyType = RPMLUAV_NUMBER; 00334 var->key.num = (double) luaL_getn(L, -1); 00335 } 00336 var->key.num++; 00337 } 00338 if (!var->listmode || lua->pushsize > 0) { 00339 if (lua->pushsize == 0) 00340 lua_pushvalue(L, LUA_GLOBALSINDEX); 00341 if (pushvar(L, var->keyType, &var->key) != -1) { 00342 if (pushvar(L, var->valueType, &var->value) != -1) 00343 lua_rawset(L, -3); 00344 else 00345 lua_pop(L, 1); 00346 } 00347 if (lua->pushsize == 0) 00348 lua_pop(L, 1); 00349 } 00350 } 00351 00352 static void popvar(lua_State *L, rpmluavType *type, void *value) 00353 /*@modifies L, *type, *value @*/ 00354 { 00355 switch (lua_type(L, -1)) { 00356 case LUA_TSTRING: 00357 *type = RPMLUAV_STRING; 00358 /*@-observertrans -dependenttrans @*/ 00359 *((const char **)value) = lua_tostring(L, -1); 00360 /*@=observertrans =dependenttrans @*/ 00361 break; 00362 case LUA_TNUMBER: 00363 *type = RPMLUAV_NUMBER; 00364 *((double *)value) = lua_tonumber(L, -1); 00365 break; 00366 default: 00367 *type = RPMLUAV_NIL; 00368 *((void **)value) = NULL; 00369 break; 00370 } 00371 lua_pop(L, 1); 00372 } 00373 00374 void rpmluaGetVar(rpmlua _lua, rpmluav var) 00375 { 00376 INITSTATE(_lua, lua); 00377 lua_State *L = lua->L; 00378 if (!var->listmode) { 00379 if (lua->pushsize == 0) 00380 lua_pushvalue(L, LUA_GLOBALSINDEX); 00381 if (pushvar(L, var->keyType, &var->key) != -1) { 00382 lua_rawget(L, -2); 00383 popvar(L, &var->valueType, &var->value); 00384 } 00385 if (lua->pushsize == 0) 00386 lua_pop(L, 1); 00387 } else if (lua->pushsize > 0) { 00388 (void) pushvar(L, var->keyType, &var->key); 00389 if (lua_next(L, -2) != 0) 00390 popvar(L, &var->valueType, &var->value); 00391 } 00392 } 00393 00394 #define FINDKEY_RETURN 0 00395 #define FINDKEY_CREATE 1 00396 #define FINDKEY_REMOVE 2 00397 static int findkey(lua_State *L, int oper, const char *key, va_list va) 00398 /*@modifies L @*/ 00399 { 00400 char buf[BUFSIZ]; 00401 const char *s, *e; 00402 int ret = 0; 00403 (void) vsnprintf(buf, sizeof(buf), key, va); 00404 s = e = buf; 00405 lua_pushvalue(L, LUA_GLOBALSINDEX); 00406 for (;;) { 00407 if (*e == '\0' || *e == '.') { 00408 if (e != s) { 00409 lua_pushlstring(L, s, e-s); 00410 switch (oper) { 00411 case FINDKEY_REMOVE: 00412 if (*e == '\0') { 00413 lua_pushnil(L); 00414 lua_rawset(L, -3); 00415 lua_pop(L, 1); 00416 /*@switchbreak@*/ break; 00417 } 00418 /*@fallthrough@*/ 00419 case FINDKEY_RETURN: 00420 lua_rawget(L, -2); 00421 lua_remove(L, -2); 00422 /*@switchbreak@*/ break; 00423 case FINDKEY_CREATE: 00424 lua_rawget(L, -2); 00425 if (!lua_istable(L, -1)) { 00426 lua_pop(L, 1); 00427 lua_newtable(L); 00428 lua_pushlstring(L, s, e-s); 00429 lua_pushvalue(L, -2); 00430 lua_rawset(L, -4); 00431 } 00432 lua_remove(L, -2); 00433 /*@switchbreak@*/ break; 00434 } 00435 } 00436 if (*e == '\0') 00437 break; 00438 if (!lua_istable(L, -1)) { 00439 lua_pop(L, 1); 00440 ret = -1; 00441 break; 00442 } 00443 s = e+1; 00444 } 00445 e++; 00446 } 00447 00448 return ret; 00449 } 00450 00451 void rpmluaDelVar(rpmlua _lua, const char *key, ...) 00452 { 00453 INITSTATE(_lua, lua); 00454 va_list va; 00455 va_start(va, key); 00456 (void) findkey(lua->L, FINDKEY_REMOVE, key, va); 00457 va_end(va); 00458 } 00459 00460 int rpmluaVarExists(rpmlua _lua, const char *key, ...) 00461 { 00462 INITSTATE(_lua, lua); 00463 lua_State *L = lua->L; 00464 int ret = 0; 00465 va_list va; 00466 va_start(va, key); 00467 if (findkey(L, FINDKEY_RETURN, key, va) == 0) { 00468 if (!lua_isnil(L, -1)) 00469 ret = 1; 00470 lua_pop(L, 1); 00471 } 00472 va_end(va); 00473 return ret; 00474 } 00475 00476 void rpmluaPushTable(rpmlua _lua, const char *key, ...) 00477 { 00478 INITSTATE(_lua, lua); 00479 va_list va; 00480 va_start(va, key); 00481 (void) findkey(lua->L, FINDKEY_CREATE, key, va); 00482 lua->pushsize++; 00483 va_end(va); 00484 } 00485 00486 void rpmluaPop(rpmlua _lua) 00487 { 00488 INITSTATE(_lua, lua); 00489 assert(lua->pushsize > 0); 00490 lua->pushsize--; 00491 lua_pop(lua->L, 1); 00492 } 00493 00494 void *rpmluavFree(rpmluav var) 00495 { 00496 (void)rpmioFreePoolItem((rpmioItem)var, __FUNCTION__, __FILE__, __LINE__); 00497 return NULL; 00498 } 00499 00500 static rpmluav rpmluavGetPool(/*@null@*/ rpmioPool pool) 00501 /*@globals _rpmluavPool, fileSystem @*/ 00502 /*@modifies pool, _rpmluavPool, fileSystem @*/ 00503 { 00504 rpmluav luav; 00505 00506 if (_rpmluavPool == NULL) { 00507 _rpmluavPool = rpmioNewPool("luav", sizeof(*luav), -1, _rpmlua_debug, 00508 NULL, NULL, NULL); 00509 pool = _rpmluavPool; 00510 } 00511 return (rpmluav) rpmioGetPool(pool, sizeof(*luav)); 00512 } 00513 00514 rpmluav rpmluavNew(void) 00515 { 00516 rpmluav var = rpmluavGetPool(_rpmluavPool); 00517 var->keyType = RPMLUAV_NIL; 00518 var->valueType = RPMLUAV_NIL; 00519 var->key.ptr = NULL; 00520 var->value.ptr = NULL; 00521 var->listmode = 0; 00522 return ((rpmluav)rpmioLinkPoolItem((rpmioItem)var, __FUNCTION__, __FILE__, __LINE__)); 00523 } 00524 00525 void rpmluavSetListMode(rpmluav var, int flag) 00526 { 00527 var->listmode = flag; 00528 var->keyType = RPMLUAV_NIL; 00529 } 00530 00531 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value) 00532 { 00533 var->keyType = type; 00534 /*@-assignexpose -temptrans @*/ 00535 switch (type) { 00536 case RPMLUAV_NUMBER: 00537 var->key.num = *((double *)value); 00538 break; 00539 case RPMLUAV_STRING: 00540 var->key.str = (char *)value; 00541 break; 00542 default: 00543 break; 00544 } 00545 /*@=assignexpose =temptrans @*/ 00546 } 00547 00548 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value) 00549 { 00550 var->valueType = type; 00551 /*@-assignexpose -temptrans @*/ 00552 switch (type) { 00553 case RPMLUAV_NUMBER: 00554 var->value.num = *((const double *)value); 00555 break; 00556 case RPMLUAV_STRING: 00557 var->value.str = (const char *)value; 00558 break; 00559 default: 00560 break; 00561 } 00562 /*@=assignexpose =temptrans @*/ 00563 } 00564 00565 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value) 00566 { 00567 *type = var->keyType; 00568 /*@-onlytrans@*/ 00569 switch (var->keyType) { 00570 case RPMLUAV_NUMBER: 00571 *((double **)value) = &var->key.num; 00572 break; 00573 case RPMLUAV_STRING: 00574 *((const char **)value) = var->key.str; 00575 break; 00576 default: 00577 break; 00578 } 00579 /*@=onlytrans@*/ 00580 } 00581 00582 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value) 00583 { 00584 *type = var->valueType; 00585 /*@-onlytrans@*/ 00586 switch (var->valueType) { 00587 case RPMLUAV_NUMBER: 00588 *((double **)value) = &var->value.num; 00589 break; 00590 case RPMLUAV_STRING: 00591 *((const char **)value) = var->value.str; 00592 break; 00593 default: 00594 break; 00595 } 00596 /*@=onlytrans@*/ 00597 } 00598 00599 void rpmluavSetKeyNum(rpmluav var, double value) 00600 { 00601 rpmluavSetKey(var, RPMLUAV_NUMBER, &value); 00602 } 00603 00604 void rpmluavSetValueNum(rpmluav var, double value) 00605 { 00606 rpmluavSetValue(var, RPMLUAV_NUMBER, &value); 00607 } 00608 00609 double rpmluavGetKeyNum(rpmluav var) 00610 { 00611 rpmluavType type; 00612 void *value; 00613 rpmluavGetKey(var, &type, &value); 00614 if (type == RPMLUAV_NUMBER) 00615 return *((double *)value); 00616 return (double) 0; 00617 } 00618 00619 double rpmluavGetValueNum(rpmluav var) 00620 { 00621 rpmluavType type; 00622 void *value; 00623 rpmluavGetValue(var, &type, &value); 00624 if (type == RPMLUAV_NUMBER) 00625 return *((double *)value); 00626 return (double) 0; 00627 } 00628 00629 int rpmluavKeyIsNum(rpmluav var) 00630 { 00631 return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0; 00632 } 00633 00634 int rpmluavValueIsNum(rpmluav var) 00635 { 00636 return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0; 00637 } 00638 00639 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name) 00640 { 00641 INITSTATE(_lua, lua); 00642 lua_State *L = lua->L; 00643 int ret = 0; 00644 if (name == NULL) 00645 name = "<lua>"; 00646 if (luaL_loadbuffer(L, script, strlen(script), name) != 0) { 00647 rpmlog(RPMLOG_ERR, 00648 _("invalid syntax in Lua scriptlet: %s\n"), 00649 lua_tostring(L, -1)); 00650 ret = -1; 00651 } 00652 lua_pop(L, 1); /* Error or chunk. */ 00653 return ret; 00654 } 00655 00656 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name) 00657 { 00658 INITSTATE(_lua, lua); 00659 lua_State *L = lua->L; 00660 int ret = 0; 00661 if (name == NULL) 00662 name = "<lua>"; 00663 if (luaL_loadbuffer(L, script, strlen(script), name) != 0) { 00664 rpmlog(RPMLOG_ERR, _("invalid syntax in Lua script: %s\n"), 00665 lua_tostring(L, -1)); 00666 lua_pop(L, 1); 00667 ret = -1; 00668 } else if (lua_pcall(L, 0, 0, 0) != 0) { 00669 rpmlog(RPMLOG_ERR, _("Lua script failed: %s\n"), 00670 lua_tostring(L, -1)); 00671 lua_pop(L, 1); 00672 ret = -1; 00673 } 00674 return ret; 00675 } 00676 00677 int rpmluaRunScriptFile(rpmlua _lua, const char *filename) 00678 { 00679 INITSTATE(_lua, lua); 00680 lua_State *L = lua->L; 00681 int ret = 0; 00682 if (luaL_loadfile(L, filename) != 0) { 00683 rpmlog(RPMLOG_ERR, _("invalid syntax in Lua file: %s\n"), 00684 lua_tostring(L, -1)); 00685 lua_pop(L, 1); 00686 ret = -1; 00687 } else if (lua_pcall(L, 0, 0, 0) != 0) { 00688 rpmlog(RPMLOG_ERR, _("Lua script failed: %s\n"), 00689 lua_tostring(L, -1)); 00690 lua_pop(L, 1); 00691 ret = -1; 00692 } 00693 return ret; 00694 } 00695 00696 /* From lua.c */ 00697 static int rpmluaReadline(lua_State *L, const char *prompt) 00698 /*@globals fileSystem @*/ 00699 /*@modifies L, fileSystem @*/ 00700 { 00701 static char buffer[1024]; 00702 if (prompt) { 00703 (void) fputs(prompt, stdout); 00704 (void) fflush(stdout); 00705 } 00706 if (fgets(buffer, (int)sizeof(buffer), stdin) == NULL) { 00707 return 0; /* read fails */ 00708 } else { 00709 lua_pushstring(L, buffer); 00710 return 1; 00711 } 00712 } 00713 00714 /* Based on lua.c */ 00715 static void _rpmluaInteractive(lua_State *L) 00716 /*@globals fileSystem @*/ 00717 /*@modifies L, fileSystem @*/ 00718 { 00719 (void) fputs("\n", stdout); 00720 printf("RPM Interactive %s Interpreter\n", LUA_VERSION); 00721 for (;;) { 00722 int rc = 0; 00723 00724 if (rpmluaReadline(L, "> ") == 0) 00725 break; 00726 if (lua_tostring(L, -1)[0] == '=') { 00727 /*@-evalorder@*/ 00728 (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1); 00729 /*@=evalorder@*/ 00730 lua_remove(L, -2); 00731 } 00732 for (;;) { 00733 /*@-evalorder@*/ 00734 rc = luaL_loadbuffer(L, lua_tostring(L, -1), 00735 lua_strlen(L, -1), "<lua>"); 00736 /*@=evalorder@*/ 00737 if (rc == LUA_ERRSYNTAX && 00738 strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) { 00739 if (rpmluaReadline(L, ">> ") == 0) 00740 /*@innerbreak@*/ break; 00741 lua_remove(L, -2); /* Remove error */ 00742 lua_concat(L, 2); 00743 /*@innercontinue@*/ continue; 00744 } 00745 /*@innerbreak@*/ break; 00746 } 00747 if (rc == 0) 00748 rc = lua_pcall(L, 0, 0, 0); 00749 if (rc != 0) { 00750 /*@-evalorderuncon@*/ 00751 fprintf(stderr, "%s\n", lua_tostring(L, -1)); 00752 /*@=evalorderuncon@*/ 00753 lua_pop(L, 1); 00754 } 00755 lua_pop(L, 1); /* Remove line */ 00756 } 00757 (void) fputs("\n", stdout); 00758 } 00759 00760 /*@-mods@*/ 00761 void rpmluaInteractive(rpmlua _lua) 00762 { 00763 INITSTATE(_lua, lua); 00764 _rpmluaInteractive(lua->L); 00765 } 00766 /*@=mods@*/ 00767 00768 /* ------------------------------------------------------------------ */ 00769 /* Lua API */ 00770 00771 static int rpm_macros(lua_State *L) 00772 /*@modifies L @*/ 00773 { 00774 const char ** av = NULL; 00775 int ac = 0; 00776 int i; 00777 00778 /*@-modunconnomods@*/ 00779 lua_newtable(L); 00780 /*@=modunconnomods@*/ 00781 00782 /*@-globs@*/ 00783 ac = rpmGetMacroEntries(NULL, NULL, -1, &av); 00784 /*@=globs@*/ 00785 00786 if (av != NULL) 00787 for (i = 0; i < ac; i++) { 00788 char *n, *o, *b; 00789 00790 /* Parse out "%name(opts)\tbody" into n/o/b strings. */ 00791 n = (char *) av[i]; 00792 b = strchr(n, '\t'); 00793 assert(b != NULL); 00794 o = ((b > n && b[-1] == ')') ? strchr(n, '(') : NULL); 00795 if (*n == '%') n++; 00796 if (o != NULL && *o == '(') { 00797 b[-1] = '\0'; 00798 o++; 00799 o[-1] = '\0'; 00800 } 00801 else 00802 b[0] = '\0'; 00803 b++; 00804 00805 /*@-modunconnomods@*/ 00806 lua_pushstring(L, n); 00807 lua_newtable(L); 00808 if (o) { 00809 lua_pushstring(L, "opts"); 00810 lua_pushstring(L, o); 00811 lua_settable(L, -3); 00812 } 00813 if (b) { 00814 lua_pushstring(L, "body"); 00815 lua_pushstring(L, b); 00816 lua_settable(L, -3); 00817 } 00818 lua_settable(L, -3); 00819 /*@=modunconnomods@*/ 00820 } 00821 av = argvFree(av); 00822 return 1; 00823 } 00824 00825 static int rpm_expand(lua_State *L) 00826 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00827 /*@modifies L, rpmGlobalMacroContext, internalState @*/ 00828 { 00829 const char *str = luaL_checkstring(L, 1); 00830 lua_pushstring(L, rpmExpand(str, NULL)); 00831 return 1; 00832 } 00833 00834 static int rpm_define(lua_State *L) 00835 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00836 /*@modifies L, rpmGlobalMacroContext, internalState @*/ 00837 { 00838 const char *str = luaL_checkstring(L, 1); 00839 (void) rpmDefineMacro(NULL, str, 0); 00840 return 0; 00841 } 00842 00843 static int rpm_undefine(lua_State *L) 00844 /*@globals rpmGlobalMacroContext, internalState @*/ 00845 /*@modifies L, rpmGlobalMacroContext, internalState @*/ 00846 { 00847 const char *str = luaL_checkstring(L, 1); 00848 (void) rpmUndefineMacro(NULL, str); 00849 return 0; 00850 } 00851 00852 static int rpm_interactive(lua_State *L) 00853 /*@globals fileSystem @*/ 00854 /*@modifies L, fileSystem @*/ 00855 { 00856 _rpmluaInteractive(L); 00857 return 0; 00858 } 00859 00860 typedef struct rpmluaHookData_s { 00861 /*@shared@*/ 00862 lua_State *L; 00863 int funcRef; 00864 int dataRef; 00865 } * rpmluaHookData; 00866 00867 static int rpmluaHookWrapper(rpmhookArgs args, void *data) 00868 /*@*/ 00869 { 00870 rpmluaHookData hookdata = (rpmluaHookData)data; 00871 lua_State *L = hookdata->L; 00872 int ret = 0; 00873 int i; 00874 lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef); 00875 lua_newtable(L); 00876 for (i = 0; i != args->argc; i++) { 00877 switch (args->argt[i]) { 00878 case 's': 00879 lua_pushstring(L, args->argv[i].s); 00880 lua_rawseti(L, -2, i+1); 00881 /*@switchbreak@*/ break; 00882 case 'i': 00883 lua_pushnumber(L, (lua_Number)args->argv[i].i); 00884 lua_rawseti(L, -2, i+1); 00885 /*@switchbreak@*/ break; 00886 case 'f': 00887 lua_pushnumber(L, (lua_Number)args->argv[i].f); 00888 lua_rawseti(L, -2, i+1); 00889 /*@switchbreak@*/ break; 00890 case 'p': 00891 lua_pushlightuserdata(L, args->argv[i].p); 00892 lua_rawseti(L, -2, i+1); 00893 /*@switchbreak@*/ break; 00894 default: 00895 (void) luaL_error(L, "unsupported type '%c' as " 00896 "a hook argument\n", args->argt[i]); 00897 /*@switchbreak@*/ break; 00898 } 00899 } 00900 if (lua_pcall(L, 1, 1, 0) != 0) { 00901 rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"), 00902 lua_tostring(L, -1)); 00903 lua_pop(L, 1); 00904 } else { 00905 if (lua_isnumber(L, -1)) 00906 ret = (int)lua_tonumber(L, -1); 00907 lua_pop(L, 1); 00908 } 00909 return ret; 00910 } 00911 00912 static int rpm_register(lua_State *L) 00913 /*@globals internalState @*/ 00914 /*@modifies L, internalState @*/ 00915 { 00916 if (!lua_isstring(L, 1)) { 00917 (void) luaL_argerror(L, 1, "hook name expected"); 00918 } else if (!lua_isfunction(L, 2)) { 00919 (void) luaL_argerror(L, 2, "function expected"); 00920 } else { 00921 rpmluaHookData hookdata = 00922 lua_newuserdata(L, sizeof(struct rpmluaHookData_s)); 00923 lua_pushvalue(L, -1); 00924 hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX); 00925 lua_pushvalue(L, 2); 00926 hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX); 00927 /*@-temptrans@*/ 00928 hookdata->L = L; 00929 /*@=temptrans@*/ 00930 rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata); 00931 return 1; 00932 } 00933 return 0; 00934 } 00935 00936 static int rpm_unregister(lua_State *L) 00937 /*@modifies L @*/ 00938 { 00939 if (!lua_isstring(L, 1)) { 00940 (void) luaL_argerror(L, 1, "hook name expected"); 00941 } else if (!lua_islightuserdata(L, 2)) { 00942 (void) luaL_argerror(L, 2, "hook information expected"); 00943 } else { 00944 rpmluaHookData hookdata = (rpmluaHookData)lua_touserdata(L, 2); 00945 luaL_unref(L, LUA_REGISTRYINDEX, hookdata->funcRef); 00946 luaL_unref(L, LUA_REGISTRYINDEX, hookdata->dataRef); 00947 rpmhookUnregister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata); 00948 } 00949 return 0; 00950 } 00951 00952 static int rpm_call(lua_State *L) 00953 /*@globals internalState @*/ 00954 /*@modifies L, internalState @*/ 00955 { 00956 if (!lua_isstring(L, 1)) { 00957 (void) luaL_argerror(L, 1, "hook name expected"); 00958 } else { 00959 rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1); 00960 const char *name = lua_tostring(L, 1); 00961 char *argt = (char *)xmalloc(args->argc+1); 00962 int i; 00963 for (i = 0; i != args->argc; i++) { 00964 switch (lua_type(L, i+1)) { 00965 case LUA_TNIL: 00966 argt[i] = 'p'; 00967 args->argv[i].p = NULL; 00968 /*@switchbreak@*/ break; 00969 case LUA_TNUMBER: { 00970 float f = (float)lua_tonumber(L, i+1); 00971 /*@+relaxtypes@*/ 00972 if (f == (int)f) { 00973 argt[i] = 'i'; 00974 args->argv[i].i = (int)f; 00975 } else { 00976 argt[i] = 'f'; 00977 args->argv[i].f = f; 00978 } 00979 /*@=relaxtypes@*/ 00980 } /*@switchbreak@*/ break; 00981 case LUA_TSTRING: 00982 argt[i] = 's'; 00983 args->argv[i].s = lua_tostring(L, i+1); 00984 /*@switchbreak@*/ break; 00985 case LUA_TUSERDATA: 00986 case LUA_TLIGHTUSERDATA: 00987 argt[i] = 'p'; 00988 args->argv[i].p = lua_touserdata(L, i+1); 00989 /*@switchbreak@*/ break; 00990 default: 00991 (void) luaL_error(L, "unsupported Lua type passed to hook"); 00992 argt[i] = 'p'; 00993 args->argv[i].p = NULL; 00994 /*@switchbreak@*/ break; 00995 } 00996 } 00997 /*@-compdef -kepttrans -usereleased @*/ 00998 args->argt = argt; 00999 rpmhookCallArgs(name, args); 01000 argt = _free(argt); 01001 (void) rpmhookArgsFree(args); 01002 /*@=compdef =kepttrans =usereleased @*/ 01003 } 01004 return 0; 01005 } 01006 01007 /* Based on luaB_print. */ 01008 static int rpm_print (lua_State *L) 01009 /*@globals fileSystem @*/ 01010 /*@modifies L, fileSystem @*/ 01011 { 01012 rpmlua lua = (rpmlua)getdata(L, "lua"); 01013 int n = lua_gettop(L); /* number of arguments */ 01014 int i; 01015 if (!lua) return 0; 01016 lua_getglobal(L, "tostring"); 01017 for (i = 1; i <= n; i++) { 01018 const char *s; 01019 lua_pushvalue(L, -1); /* function to be called */ 01020 lua_pushvalue(L, i); /* value to print */ 01021 lua_call(L, 1, 1); 01022 s = lua_tostring(L, -1); /* get result */ 01023 if (s == NULL) 01024 return luaL_error(L, "`tostring' must return a string to `print'"); 01025 if (lua->storeprint) { 01026 size_t sl = lua_strlen(L, -1); 01027 if ((size_t)(lua->printbufused+sl+1) > lua->printbufsize) { 01028 lua->printbufsize += sl+512; 01029 lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize); 01030 } 01031 if (i > 1) 01032 lua->printbuf[lua->printbufused++] = '\t'; 01033 memcpy(lua->printbuf+lua->printbufused, s, sl+1); 01034 lua->printbufused += sl; 01035 } else { 01036 if (i > 1) 01037 (void) fputs("\t", stdout); 01038 (void) fputs(s, stdout); 01039 } 01040 lua_pop(L, 1); /* pop result */ 01041 } 01042 if (!lua->storeprint) { 01043 (void) fputs("\n", stdout); 01044 } else { 01045 if ((size_t)(lua->printbufused+1) > lua->printbufsize) { 01046 lua->printbufsize += 512; 01047 lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize); 01048 } 01049 lua->printbuf[lua->printbufused] = '\0'; 01050 } 01051 return 0; 01052 } 01053 01054 static int rpm_source(lua_State *L) 01055 /*@globals fileSystem, internalState @*/ 01056 /*@modifies L, fileSystem, internalState @*/ 01057 { 01058 if (!lua_isstring(L, 1)) { 01059 (void)luaL_argerror(L, 1, "filename expected"); 01060 } else { 01061 rpmlua lua = (rpmlua)getdata(L, "lua"); 01062 const char *filename = lua_tostring(L, 1); 01063 (void)rpmluaRunScriptFile(lua, filename); 01064 } 01065 return 0; 01066 } 01067 01068 extern int _max_load_depth; /* Maximum load nesting depth. */ 01069 static int rpm_load(lua_State *L) 01070 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/ 01071 /*@modifies L, rpmGlobalMacroContext, fileSystem, internalState @*/ 01072 { 01073 if (!lua_isstring(L, 1)) { 01074 (void)luaL_argerror(L, 1, "filename expected"); 01075 } else { 01076 const char *filename = lua_tostring(L, 1); 01077 /*@-globs@*/ 01078 (void)rpmLoadMacroFile(NULL, filename, _max_load_depth); 01079 /*@=globs@*/ 01080 } 01081 return 0; 01082 } 01083 01084 static int rpm_verbose(lua_State *L) 01085 /*@globals internalState @*/ 01086 /*@modifies L, internalState @*/ 01087 { 01088 lua_pushboolean(L, rpmIsVerbose()); 01089 return 1; 01090 } 01091 01092 static int rpm_debug(lua_State *L) 01093 /*@globals internalState @*/ 01094 /*@modifies L, internalState @*/ 01095 { 01096 lua_pushboolean(L, rpmIsDebug()); 01097 return 1; 01098 } 01099 01100 static int rpm_slurp(lua_State *L) 01101 /*@globals fileSystem, internalState @*/ 01102 /*@modifies L, fileSystem, internalState @*/ 01103 { 01104 rpmiob iob = NULL; 01105 const char *fn; 01106 int rc; 01107 01108 if (lua_isstring(L, 1)) 01109 fn = lua_tostring(L, 1); 01110 else { 01111 (void)luaL_argerror(L, 1, "filename"); 01112 return 0; 01113 } 01114 /*@-globs@*/ 01115 rc = rpmiobSlurp(fn, &iob); 01116 /*@=globs@*/ 01117 if (rc || iob == NULL) { 01118 (void)luaL_error(L, "failed to slurp data"); 01119 return 0; 01120 } 01121 lua_pushlstring(L, (const char *)rpmiobStr(iob), rpmiobLen(iob)); 01122 iob = rpmiobFree(iob); 01123 return 1; 01124 } 01125 01126 static int rpm_sleep(lua_State *L) 01127 /*@globals fileSystem, internalState @*/ 01128 /*@modifies L, fileSystem, internalState @*/ 01129 { 01130 unsigned sec; 01131 01132 if (lua_isnumber(L, 1)) 01133 sec = (unsigned) lua_tonumber(L, 1); 01134 else { 01135 (void)luaL_argerror(L, 1, "seconds"); 01136 return 0; 01137 } 01138 (void) sleep(sec); 01139 return 0; 01140 } 01141 01142 static int rpm_realpath(lua_State *L) 01143 /*@globals fileSystem, internalState @*/ 01144 /*@modifies L, fileSystem, internalState @*/ 01145 { 01146 const char *pn; 01147 char rp_buf[PATH_MAX]; 01148 char *rp = ""; 01149 01150 if (lua_isstring(L, 1)) 01151 pn = lua_tostring(L, 1); 01152 else { 01153 (void)luaL_argerror(L, 1, "pathname"); 01154 return 0; 01155 } 01156 if ((rp = Realpath(pn, rp_buf)) == NULL) { 01157 (void)luaL_error(L, "failed to resolve path via realpath(3): %s", strerror(errno)); 01158 return 0; 01159 } 01160 lua_pushstring(L, (const char *)rp); 01161 return 1; 01162 } 01163 01164 static int rpm_hostname(lua_State *L) 01165 /*@globals h_errno, internalState @*/ 01166 /*@modifies L, h_errno, internalState @*/ 01167 { 01168 char hostname[1024]; 01169 struct hostent *hbn; 01170 char *h; 01171 01172 /*@-multithreaded@*/ 01173 (void)gethostname(hostname, sizeof(hostname)); 01174 if ((hbn = gethostbyname(hostname)) != NULL) 01175 h = hbn->h_name; 01176 else 01177 h = hostname; 01178 /*@=multithreaded@*/ 01179 lua_pushstring(L, (const char *)h); 01180 return 1; 01181 } 01182 01183 /*@-readonlytrans -nullassign @*/ 01184 /*@observer@*/ /*@unchecked@*/ 01185 static const luaL_reg rpmlib[] = { 01186 {"macros", rpm_macros}, 01187 {"expand", rpm_expand}, 01188 {"define", rpm_define}, 01189 {"undefine", rpm_undefine}, 01190 {"register", rpm_register}, 01191 {"unregister", rpm_unregister}, 01192 {"call", rpm_call}, 01193 {"interactive", rpm_interactive}, 01194 {"source", rpm_source}, 01195 {"load", rpm_load}, 01196 {"verbose", rpm_verbose}, 01197 {"debug", rpm_debug}, 01198 {"slurp", rpm_slurp}, 01199 {"sleep", rpm_sleep}, 01200 {"realpath", rpm_realpath}, 01201 {"hostname", rpm_hostname}, 01202 {NULL, NULL} 01203 }; 01204 /*@=readonlytrans =nullassign @*/ 01205 01206 static int luaopen_rpm(lua_State *L) 01207 /*@modifies L @*/ 01208 { 01209 lua_pushvalue(L, LUA_GLOBALSINDEX); 01210 luaL_openlib(L, "rpm", rpmlib, 0); 01211 return 0; 01212 } 01213 #endif /* WITH_LUA */ 01214 01215 /*@=moduncon =mustmod =realcompare =sizeoftype @*/