rpm 5.3.7

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