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