rpm  5.2.1
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 <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 @*/