rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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