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