rpm  5.2.1
rpmlua.c
Go to the documentation of this file.
1 /*@-moduncon -mustmod -realcompare -sizeoftype @*/
2 #include "system.h"
3 
4 #ifdef WITH_LUA
5 #define _RPMIOB_INTERNAL
6 #include <rpmiotypes.h>
7 #include <rpmio.h>
8 #include <rpmmacro.h>
9 #include <rpmlog.h>
10 #include <rpmurl.h>
11 #include <rpmhook.h>
12 #include <rpmcb.h>
13 #include <argv.h>
14 #include <popt.h> /* XXX poptSaneFile test */
15 
16 #include <lua.h>
17 #include <lualib.h>
18 #include <lauxlib.h>
19 #ifdef WITH_SYCK
20 LUALIB_API int luaopen_syck(lua_State *L)
21  /*@modifies L @*/;
22 #endif /* WITH_SYCK */
23 #ifdef WITH_LUA_INTERNAL
24 #include <llocal.h>
25 #include <lposix.h>
26 #include <lrexlib.h>
27 #include <luuid.h>
28 #include <lwrs.h>
29 #ifdef USE_LUA_CRYPTO /* XXX external lua modules instead. */
30 #include <lcrypto.h>
31 #include <lxplib.h>
32 #endif
33 #ifdef USE_LUA_SOCKET /* XXX external lua modules instead. */
34 #include <luasocket.h>
35 #endif
36 #endif
37 
38 #include <unistd.h>
39 #include <assert.h>
40 
41 #define _RPMLUA_INTERNAL
42 #include "rpmlua.h"
43 
44 #include "debug.h"
45 
46 /*@access rpmiob @*/
47 
48 #else /* WITH_LUA */
49 #include <rpmio.h>
50 #endif
51 
52 /*@unchecked@*/
53 int _rpmlua_debug = 0;
54 
55 /*@unchecked@*/ /*@only@*/ /*@null@*/
57 
58 /*@unchecked@*/ /*@only@*/ /*@null@*/
60 
61 #ifdef WITH_LUA
62 
63 #if !defined(HAVE_VSNPRINTF)
64 static inline int vsnprintf(char * buf, /*@unused@*/ size_t nb,
65  const char * fmt, va_list ap)
66 {
67  return vsprintf(buf, fmt, ap);
68 }
69 #endif
70 
71 #define INITSTATE(_lua, lua) \
72  rpmlua lua = _lua ? _lua : \
73  (globalLuaState ? globalLuaState : \
74  /*@-mods@*/ \
75  (globalLuaState = rpmluaNew()) \
76  /*@=mods@*/ \
77  )
78 
79 /*@only@*/ /*@unchecked@*/ /*@relnull@*/
80 static rpmlua globalLuaState;
81 
82 static int luaopen_rpm(lua_State *L)
83  /*@modifies L @*/;
84 static int rpm_print(lua_State *L)
85  /*@globals fileSystem @*/
86  /*@modifies L, fileSystem @*/;
87 
88 /*@unchecked@*/ /*@observer@*/
89 const char * rpmluaFiles = RPMLUAFILES;
90 
91 /*@unchecked@*/ /*@observer@*/
92 const char * rpmluaPath = "%{?_rpmhome}%{!?_rpmhome:" USRLIBRPM "}/lua/?.lua";
93 
95 {
96 /*@-globstate@*/
97  return globalLuaState;
98 /*@=globstate@*/
99 }
100 
101 static void rpmluaFini(void * _lua)
102  /*@globals globalLuaState @*/
103  /*@modifies globalLuaState @*/
104 {
105  rpmlua lua = _lua;
106 
107  if (lua->L) lua_close(lua->L);
108  lua->L = NULL;
109  lua->printbuf = _free(lua->printbuf);
110 }
111 
112 static rpmlua rpmluaGetPool(/*@null@*/ rpmioPool pool)
113  /*@globals _rpmluaPool, fileSystem @*/
114  /*@modifies pool, _rpmluaPool, fileSystem @*/
115 {
116  rpmlua lua;
117 
118  if (_rpmluaPool == NULL) {
119  _rpmluaPool = rpmioNewPool("lua", sizeof(*lua), -1, _rpmlua_debug,
120  NULL, NULL, rpmluaFini);
121  pool = _rpmluaPool;
122  }
123  return (rpmlua) rpmioGetPool(pool, sizeof(*lua));
124 }
125 
126 void *rpmluaFree(rpmlua lua)
127 {
128  if (lua == NULL) lua = globalLuaState;
129  (void)rpmioFreePoolItem((rpmioItem)lua, __FUNCTION__, __FILE__, __LINE__);
130  if (lua == globalLuaState) globalLuaState = NULL;
131  return NULL;
132 }
133 
134 /*@-globs -mods@*/ /* XXX hide rpmGlobalMacroContext mods for now. */
135 rpmlua rpmluaNew(void)
136 {
137  rpmlua lua = rpmluaGetPool(_rpmluaPool);
138  lua_State *L = lua_open();
139  /*@-readonlytrans -nullassign @*/
140  /*@observer@*/ /*@unchecked@*/
141  static const luaL_reg lualibs[] = {
142  /* standard LUA libraries */
143  {"", luaopen_base},
144  {LUA_LOADLIBNAME, luaopen_package},
145  {LUA_TABLIBNAME, luaopen_table},
146  {LUA_IOLIBNAME, luaopen_io},
147  {LUA_OSLIBNAME, luaopen_os},
148  {LUA_STRLIBNAME, luaopen_string},
149  {LUA_MATHLIBNAME, luaopen_math},
150  {LUA_DBLIBNAME, luaopen_debug},
151 #ifdef WITH_SYCK
152  {"lsyck", luaopen_syck},
153 #endif /* WITH_SYCK */
154  /* local LUA libraries (RPM only) */
155 #ifdef WITH_LUA_INTERNAL
156  {"posix", luaopen_posix},
157  {"rex_posix", luaopen_rex_posix},
158  {"rex_pcre", luaopen_rex_pcre},
159  {"uuid", luaopen_uuid},
160  {"wrs", luaopen_wrs},
161 #ifdef USE_LUA_CRYPTO /* XXX external lua modules instead. */
162  {"crypto", luaopen_crypto},
163  {"lxp", luaopen_lxp},
164 #endif
165 #ifdef USE_LUA_SOCKET /* XXX external lua modules instead. */
166  {"socket", luaopen_socket_core},
167 #endif
168  {"local", luaopen_local},
169 #endif
170  {"rpm", luaopen_rpm},
171  {NULL, NULL},
172  };
173  /*@=readonlytrans =nullassign @*/
174  /*@observer@*/ /*@unchecked@*/
175  const luaL_reg *lib = lualibs;
176  char *path_buf;
177  char *path_next;
178  char *path;
179 
180  lua->L = L;
181  for (; lib->name; lib++) {
182 /*@-noeffectuncon@*/
183  lua_pushcfunction(L, lib->func);
184  lua_pushstring(L, lib->name);
185  lua_call(L, 1, 0);
186 /*@=noeffectuncon@*/
187  }
188  { const char * _lua_path = rpmGetPath(rpmluaPath, NULL);
189  if (_lua_path != NULL) {
190  lua_pushliteral(L, "LUA_PATH");
191  lua_pushstring(L, _lua_path);
192  _lua_path = _free(_lua_path);
193  }
194  }
195  lua_rawset(L, LUA_GLOBALSINDEX);
196  lua_pushliteral(L, "print");
197  lua_pushcfunction(L, rpm_print);
198  lua_rawset(L, LUA_GLOBALSINDEX);
199  rpmluaSetData(lua, "lua", lua);
200 
201  /* load all standard RPM Lua script files */
202  path_buf = xstrdup(rpmluaFiles);
203  for (path = path_buf; path != NULL && *path != '\0'; path = path_next) {
204  const char **av;
205  struct stat st;
206  int ac, i;
207 
208  /* locate start of next path element */
209  path_next = strchr(path, ':');
210  if (path_next != NULL && *path_next == ':')
211  *path_next++ = '\0';
212  else
213  path_next = path + strlen(path);
214 
215  /* glob-expand the path element */
216  ac = 0;
217  av = NULL;
218  if ((i = rpmGlob(path, &ac, &av)) != 0)
219  continue;
220 
221  /* work-off each resulting file from the path element */
222  for (i = 0; i < ac; i++) {
223  const char *fn = av[i];
224  if (fn[0] == '@' /* attention */) {
225  fn++;
226 #if defined(RPM_VENDOR_OPENPKG) /* stick-with-rpm-file-sanity-checking */ || \
227  !defined(POPT_ERROR_BADCONFIG) /* XXX POPT 1.15 retrofit */
228  if (!rpmSecuritySaneFile(fn))
229 #else
230  if (!poptSaneFile(fn))
231 #endif
232  {
233  rpmlog(RPMLOG_WARNING, "existing RPM Lua script file \"%s\" considered INSECURE -- not loaded\n", fn);
234  /*@innercontinue@*/ continue;
235  }
236  }
237  if (Stat(fn, &st) != -1)
238  (void)rpmluaRunScriptFile(lua, fn);
239  av[i] = _free(av[i]);
240  }
241  av = _free(av);
242  }
243  path_buf = _free(path_buf);
244 
245  return ((rpmlua)rpmioLinkPoolItem((rpmioItem)lua, __FUNCTION__, __FILE__, __LINE__));
246 }
247 /*@=globs =mods@*/
248 
249 void rpmluaSetData(rpmlua _lua, const char *key, const void *data)
250 {
251  INITSTATE(_lua, lua);
252  lua_State *L = lua->L;
253  lua_pushliteral(L, "rpm_");
254  lua_pushstring(L, key);
255  lua_concat(L, 2);
256  if (data == NULL)
257  lua_pushnil(L);
258  else
259  lua_pushlightuserdata(L, (void *)data);
260  lua_rawset(L, LUA_REGISTRYINDEX);
261 }
262 
263 /*@null@*/
264 static void *getdata(lua_State *L, const char *key)
265  /*@modifies L @*/
266 {
267  void *ret = NULL;
268  lua_pushliteral(L, "rpm_");
269  lua_pushstring(L, key);
270  lua_concat(L, 2);
271  lua_rawget(L, LUA_REGISTRYINDEX);
272  if (lua_islightuserdata(L, -1))
273  ret = lua_touserdata(L, -1);
274  lua_pop(L, 1);
275  return ret;
276 }
277 
278 void *rpmluaGetData(rpmlua _lua, const char *key)
279 {
280  INITSTATE(_lua, lua);
281  return getdata(lua->L, key);
282 }
283 
284 void rpmluaSetPrintBuffer(rpmlua _lua, int flag)
285 {
286  INITSTATE(_lua, lua);
287  lua->storeprint = flag;
288  lua->printbuf = _free(lua->printbuf);
289  lua->printbufsize = 0;
290  lua->printbufused = 0;
291 }
292 
293 const char *rpmluaGetPrintBuffer(rpmlua _lua)
294 {
295  INITSTATE(_lua, lua);
296  return lua->printbuf;
297 }
298 
299 static int pushvar(lua_State *L, rpmluavType type, void *value)
300  /*@modifies L @*/
301 {
302  int ret = 0;
303  switch (type) {
304  case RPMLUAV_NIL:
305  lua_pushnil(L);
306  break;
307  case RPMLUAV_STRING:
308  lua_pushstring(L, *((char **)value));
309  break;
310  case RPMLUAV_NUMBER:
311  lua_pushnumber(L, *((double *)value));
312  break;
313  default:
314  ret = -1;
315  break;
316  }
317  return ret;
318 }
319 
320 void rpmluaSetVar(rpmlua _lua, rpmluav var)
321 {
322  INITSTATE(_lua, lua);
323  lua_State *L = lua->L;
324  if (var->listmode && lua->pushsize > 0) {
325  if (var->keyType != RPMLUAV_NUMBER || var->key.num == (double)0) {
326  var->keyType = RPMLUAV_NUMBER;
327  var->key.num = (double) luaL_getn(L, -1);
328  }
329  var->key.num++;
330  }
331  if (!var->listmode || lua->pushsize > 0) {
332  if (lua->pushsize == 0)
333  lua_pushvalue(L, LUA_GLOBALSINDEX);
334  if (pushvar(L, var->keyType, &var->key) != -1) {
335  if (pushvar(L, var->valueType, &var->value) != -1)
336  lua_rawset(L, -3);
337  else
338  lua_pop(L, 1);
339  }
340  if (lua->pushsize == 0)
341  lua_pop(L, 1);
342  }
343 }
344 
345 static void popvar(lua_State *L, rpmluavType *type, void *value)
346  /*@modifies L, *type, *value @*/
347 {
348  switch (lua_type(L, -1)) {
349  case LUA_TSTRING:
350  *type = RPMLUAV_STRING;
351 /*@-observertrans -dependenttrans @*/
352  *((const char **)value) = lua_tostring(L, -1);
353 /*@=observertrans =dependenttrans @*/
354  break;
355  case LUA_TNUMBER:
356  *type = RPMLUAV_NUMBER;
357  *((double *)value) = lua_tonumber(L, -1);
358  break;
359  default:
360  *type = RPMLUAV_NIL;
361  *((void **)value) = NULL;
362  break;
363  }
364  lua_pop(L, 1);
365 }
366 
367 void rpmluaGetVar(rpmlua _lua, rpmluav var)
368 {
369  INITSTATE(_lua, lua);
370  lua_State *L = lua->L;
371  if (!var->listmode) {
372  if (lua->pushsize == 0)
373  lua_pushvalue(L, LUA_GLOBALSINDEX);
374  if (pushvar(L, var->keyType, &var->key) != -1) {
375  lua_rawget(L, -2);
376  popvar(L, &var->valueType, &var->value);
377  }
378  if (lua->pushsize == 0)
379  lua_pop(L, 1);
380  } else if (lua->pushsize > 0) {
381  (void) pushvar(L, var->keyType, &var->key);
382  if (lua_next(L, -2) != 0)
383  popvar(L, &var->valueType, &var->value);
384  }
385 }
386 
387 #define FINDKEY_RETURN 0
388 #define FINDKEY_CREATE 1
389 #define FINDKEY_REMOVE 2
390 static int findkey(lua_State *L, int oper, const char *key, va_list va)
391  /*@modifies L @*/
392 {
393  char buf[BUFSIZ];
394  const char *s, *e;
395  int ret = 0;
396  (void) vsnprintf(buf, sizeof(buf), key, va);
397  s = e = buf;
398  lua_pushvalue(L, LUA_GLOBALSINDEX);
399  for (;;) {
400  if (*e == '\0' || *e == '.') {
401  if (e != s) {
402  lua_pushlstring(L, s, e-s);
403  switch (oper) {
404  case FINDKEY_REMOVE:
405  if (*e == '\0') {
406  lua_pushnil(L);
407  lua_rawset(L, -3);
408  lua_pop(L, 1);
409  /*@switchbreak@*/ break;
410  }
411  /*@fallthrough@*/
412  case FINDKEY_RETURN:
413  lua_rawget(L, -2);
414  lua_remove(L, -2);
415  /*@switchbreak@*/ break;
416  case FINDKEY_CREATE:
417  lua_rawget(L, -2);
418  if (!lua_istable(L, -1)) {
419  lua_pop(L, 1);
420  lua_newtable(L);
421  lua_pushlstring(L, s, e-s);
422  lua_pushvalue(L, -2);
423  lua_rawset(L, -4);
424  }
425  lua_remove(L, -2);
426  /*@switchbreak@*/ break;
427  }
428  }
429  if (*e == '\0')
430  break;
431  if (!lua_istable(L, -1)) {
432  lua_pop(L, 1);
433  ret = -1;
434  break;
435  }
436  s = e+1;
437  }
438  e++;
439  }
440 
441  return ret;
442 }
443 
444 void rpmluaDelVar(rpmlua _lua, const char *key, ...)
445 {
446  INITSTATE(_lua, lua);
447  va_list va;
448  va_start(va, key);
449  (void) findkey(lua->L, FINDKEY_REMOVE, key, va);
450  va_end(va);
451 }
452 
453 int rpmluaVarExists(rpmlua _lua, const char *key, ...)
454 {
455  INITSTATE(_lua, lua);
456  lua_State *L = lua->L;
457  int ret = 0;
458  va_list va;
459  va_start(va, key);
460  if (findkey(L, FINDKEY_RETURN, key, va) == 0) {
461  if (!lua_isnil(L, -1))
462  ret = 1;
463  lua_pop(L, 1);
464  }
465  va_end(va);
466  return ret;
467 }
468 
469 void rpmluaPushTable(rpmlua _lua, const char *key, ...)
470 {
471  INITSTATE(_lua, lua);
472  va_list va;
473  va_start(va, key);
474  (void) findkey(lua->L, FINDKEY_CREATE, key, va);
475  lua->pushsize++;
476  va_end(va);
477 }
478 
479 void rpmluaPop(rpmlua _lua)
480 {
481  INITSTATE(_lua, lua);
482  assert(lua->pushsize > 0);
483  lua->pushsize--;
484  lua_pop(lua->L, 1);
485 }
486 
487 void *rpmluavFree(rpmluav var)
488 {
489  (void)rpmioFreePoolItem((rpmioItem)var, __FUNCTION__, __FILE__, __LINE__);
490  return NULL;
491 }
492 
493 static rpmluav rpmluavGetPool(/*@null@*/ rpmioPool pool)
494  /*@globals _rpmluavPool, fileSystem @*/
495  /*@modifies pool, _rpmluavPool, fileSystem @*/
496 {
497  rpmluav luav;
498 
499  if (_rpmluavPool == NULL) {
500  _rpmluavPool = rpmioNewPool("luav", sizeof(*luav), -1, _rpmlua_debug,
501  NULL, NULL, NULL);
502  pool = _rpmluavPool;
503  }
504  return (rpmluav) rpmioGetPool(pool, sizeof(*luav));
505 }
506 
507 rpmluav rpmluavNew(void)
508 {
509  rpmluav var = rpmluavGetPool(_rpmluavPool);
510  return ((rpmluav)rpmioLinkPoolItem((rpmioItem)var, __FUNCTION__, __FILE__, __LINE__));
511 }
512 
513 void rpmluavSetListMode(rpmluav var, int flag)
514 {
515  var->listmode = flag;
516  var->keyType = RPMLUAV_NIL;
517 }
518 
519 void rpmluavSetKey(rpmluav var, rpmluavType type, const void *value)
520 {
521  var->keyType = type;
522 /*@-assignexpose -temptrans @*/
523  switch (type) {
524  case RPMLUAV_NUMBER:
525  var->key.num = *((double *)value);
526  break;
527  case RPMLUAV_STRING:
528  var->key.str = (char *)value;
529  break;
530  default:
531  break;
532  }
533 /*@=assignexpose =temptrans @*/
534 }
535 
536 void rpmluavSetValue(rpmluav var, rpmluavType type, const void *value)
537 {
538  var->valueType = type;
539 /*@-assignexpose -temptrans @*/
540  switch (type) {
541  case RPMLUAV_NUMBER:
542  var->value.num = *((const double *)value);
543  break;
544  case RPMLUAV_STRING:
545  var->value.str = (const char *)value;
546  break;
547  default:
548  break;
549  }
550 /*@=assignexpose =temptrans @*/
551 }
552 
553 void rpmluavGetKey(rpmluav var, rpmluavType *type, void **value)
554 {
555  *type = var->keyType;
556 /*@-onlytrans@*/
557  switch (var->keyType) {
558  case RPMLUAV_NUMBER:
559  *((double **)value) = &var->key.num;
560  break;
561  case RPMLUAV_STRING:
562  *((const char **)value) = var->key.str;
563  break;
564  default:
565  break;
566  }
567 /*@=onlytrans@*/
568 }
569 
570 void rpmluavGetValue(rpmluav var, rpmluavType *type, void **value)
571 {
572  *type = var->valueType;
573 /*@-onlytrans@*/
574  switch (var->valueType) {
575  case RPMLUAV_NUMBER:
576  *((double **)value) = &var->value.num;
577  break;
578  case RPMLUAV_STRING:
579  *((const char **)value) = var->value.str;
580  break;
581  default:
582  break;
583  }
584 /*@=onlytrans@*/
585 }
586 
587 void rpmluavSetKeyNum(rpmluav var, double value)
588 {
589  rpmluavSetKey(var, RPMLUAV_NUMBER, &value);
590 }
591 
592 void rpmluavSetValueNum(rpmluav var, double value)
593 {
594  rpmluavSetValue(var, RPMLUAV_NUMBER, &value);
595 }
596 
597 double rpmluavGetKeyNum(rpmluav var)
598 {
599  rpmluavType type;
600  void *value;
601  rpmluavGetKey(var, &type, &value);
602  if (type == RPMLUAV_NUMBER)
603  return *((double *)value);
604  return (double) 0;
605 }
606 
607 double rpmluavGetValueNum(rpmluav var)
608 {
609  rpmluavType type;
610  void *value;
611  rpmluavGetValue(var, &type, &value);
612  if (type == RPMLUAV_NUMBER)
613  return *((double *)value);
614  return (double) 0;
615 }
616 
617 int rpmluavKeyIsNum(rpmluav var)
618 {
619  return (var->keyType == RPMLUAV_NUMBER) ? 1 : 0;
620 }
621 
622 int rpmluavValueIsNum(rpmluav var)
623 {
624  return (var->valueType == RPMLUAV_NUMBER) ? 1 : 0;
625 }
626 
627 int rpmluaCheckScript(rpmlua _lua, const char *script, const char *name)
628 {
629  INITSTATE(_lua, lua);
630  lua_State *L = lua->L;
631  int ret = 0;
632  if (name == NULL)
633  name = "<lua>";
634  if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
636  _("invalid syntax in Lua scriptlet: %s\n"),
637  lua_tostring(L, -1));
638  ret = -1;
639  }
640  lua_pop(L, 1); /* Error or chunk. */
641  return ret;
642 }
643 
644 int rpmluaRunScript(rpmlua _lua, const char *script, const char *name)
645 {
646  INITSTATE(_lua, lua);
647  lua_State *L = lua->L;
648  int ret = 0;
649  if (name == NULL)
650  name = "<lua>";
651  if (luaL_loadbuffer(L, script, strlen(script), name) != 0) {
652  rpmlog(RPMLOG_ERR, _("invalid syntax in Lua script: %s\n"),
653  lua_tostring(L, -1));
654  lua_pop(L, 1);
655  ret = -1;
656  } else if (lua_pcall(L, 0, 0, 0) != 0) {
657  rpmlog(RPMLOG_ERR, _("Lua script failed: %s\n"),
658  lua_tostring(L, -1));
659  lua_pop(L, 1);
660  ret = -1;
661  }
662  return ret;
663 }
664 
665 int rpmluaRunScriptFile(rpmlua _lua, const char *filename)
666 {
667  INITSTATE(_lua, lua);
668  lua_State *L = lua->L;
669  int ret = 0;
670  if (luaL_loadfile(L, filename) != 0) {
671  rpmlog(RPMLOG_ERR, _("invalid syntax in Lua file: %s\n"),
672  lua_tostring(L, -1));
673  lua_pop(L, 1);
674  ret = -1;
675  } else if (lua_pcall(L, 0, 0, 0) != 0) {
676  rpmlog(RPMLOG_ERR, _("Lua script failed: %s\n"),
677  lua_tostring(L, -1));
678  lua_pop(L, 1);
679  ret = -1;
680  }
681  return ret;
682 }
683 
684 /* From lua.c */
685 static int rpmluaReadline(lua_State *L, const char *prompt)
686  /*@globals fileSystem @*/
687  /*@modifies L, fileSystem @*/
688 {
689  static char buffer[1024];
690  if (prompt) {
691  (void) fputs(prompt, stdout);
692  (void) fflush(stdout);
693  }
694  if (fgets(buffer, (int)sizeof(buffer), stdin) == NULL) {
695  return 0; /* read fails */
696  } else {
697  lua_pushstring(L, buffer);
698  return 1;
699  }
700 }
701 
702 /* Based on lua.c */
703 static void _rpmluaInteractive(lua_State *L)
704  /*@globals fileSystem @*/
705  /*@modifies L, fileSystem @*/
706 {
707  (void) fputs("\n", stdout);
708  printf("RPM Interactive %s Interpreter\n", LUA_VERSION);
709  for (;;) {
710  int rc = 0;
711 
712  if (rpmluaReadline(L, "> ") == 0)
713  break;
714  if (lua_tostring(L, -1)[0] == '=') {
715 /*@-evalorder@*/
716  (void) lua_pushfstring(L, "print(%s)", lua_tostring(L, -1)+1);
717 /*@=evalorder@*/
718  lua_remove(L, -2);
719  }
720  for (;;) {
721 /*@-evalorder@*/
722  rc = luaL_loadbuffer(L, lua_tostring(L, -1),
723  lua_strlen(L, -1), "<lua>");
724 /*@=evalorder@*/
725  if (rc == LUA_ERRSYNTAX &&
726  strstr(lua_tostring(L, -1), "near `<eof>'") != NULL) {
727  if (rpmluaReadline(L, ">> ") == 0)
728  /*@innerbreak@*/ break;
729  lua_remove(L, -2); /* Remove error */
730  lua_concat(L, 2);
731  /*@innercontinue@*/ continue;
732  }
733  /*@innerbreak@*/ break;
734  }
735  if (rc == 0)
736  rc = lua_pcall(L, 0, 0, 0);
737  if (rc != 0) {
738 /*@-evalorderuncon@*/
739  fprintf(stderr, "%s\n", lua_tostring(L, -1));
740 /*@=evalorderuncon@*/
741  lua_pop(L, 1);
742  }
743  lua_pop(L, 1); /* Remove line */
744  }
745  (void) fputs("\n", stdout);
746 }
747 
748 /*@-mods@*/
749 void rpmluaInteractive(rpmlua _lua)
750 {
751  INITSTATE(_lua, lua);
752  _rpmluaInteractive(lua->L);
753 }
754 /*@=mods@*/
755 
756 /* ------------------------------------------------------------------ */
757 /* Lua API */
758 
759 static int rpm_macros(lua_State *L)
760  /*@modifies L @*/
761 {
762  const char ** av = NULL;
763  int ac = 0;
764  int i;
765 
766 /*@-modunconnomods@*/
767  lua_newtable(L);
768 /*@=modunconnomods@*/
769 
770 /*@-globs@*/
771  ac = rpmGetMacroEntries(NULL, NULL, -1, &av);
772 /*@=globs@*/
773 
774  if (av != NULL)
775  for (i = 0; i < ac; i++) {
776  char *n, *o, *b;
777 
778  /* Parse out "%name(opts)\tbody" into n/o/b strings. */
779  n = (char *) av[i];
780  b = strchr(n, '\t');
781 assert(b != NULL);
782  o = ((b > n && b[-1] == ')') ? strchr(n, '(') : NULL);
783  if (*n == '%') n++;
784  if (o != NULL && *o == '(') {
785  b[-1] = '\0';
786  o++;
787  o[-1] = '\0';
788  }
789  else
790  b[0] = '\0';
791  b++;
792 
793 /*@-modunconnomods@*/
794  lua_pushstring(L, n);
795  lua_newtable(L);
796  if (o) {
797  lua_pushstring(L, "opts");
798  lua_pushstring(L, o);
799  lua_settable(L, -3);
800  }
801  if (b) {
802  lua_pushstring(L, "body");
803  lua_pushstring(L, b);
804  lua_settable(L, -3);
805  }
806  lua_settable(L, -3);
807 /*@=modunconnomods@*/
808  }
809  av = argvFree(av);
810  return 1;
811 }
812 
813 static int rpm_expand(lua_State *L)
814  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
815  /*@modifies L, rpmGlobalMacroContext, internalState @*/
816 {
817  const char *str = luaL_checkstring(L, 1);
818  lua_pushstring(L, rpmExpand(str, NULL));
819  return 1;
820 }
821 
822 static int rpm_define(lua_State *L)
823  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
824  /*@modifies L, rpmGlobalMacroContext, internalState @*/
825 {
826  const char *str = luaL_checkstring(L, 1);
827  (void) rpmDefineMacro(NULL, str, 0);
828  return 0;
829 }
830 
831 static int rpm_undefine(lua_State *L)
832  /*@globals rpmGlobalMacroContext, internalState @*/
833  /*@modifies L, rpmGlobalMacroContext, internalState @*/
834 {
835  const char *str = luaL_checkstring(L, 1);
836  (void) rpmUndefineMacro(NULL, str);
837  return 0;
838 }
839 
840 static int rpm_interactive(lua_State *L)
841  /*@globals fileSystem @*/
842  /*@modifies L, fileSystem @*/
843 {
844  _rpmluaInteractive(L);
845  return 0;
846 }
847 
848 typedef struct rpmluaHookData_s {
849 /*@shared@*/
850  lua_State *L;
851  int funcRef;
852  int dataRef;
853 } * rpmluaHookData;
854 
855 static int rpmluaHookWrapper(rpmhookArgs args, void *data)
856  /*@*/
857 {
858  rpmluaHookData hookdata = (rpmluaHookData)data;
859  lua_State *L = hookdata->L;
860  int ret = 0;
861  int i;
862  lua_rawgeti(L, LUA_REGISTRYINDEX, hookdata->funcRef);
863  lua_newtable(L);
864  for (i = 0; i != args->argc; i++) {
865  switch (args->argt[i]) {
866  case 's':
867  lua_pushstring(L, args->argv[i].s);
868  lua_rawseti(L, -2, i+1);
869  /*@switchbreak@*/ break;
870  case 'i':
871  lua_pushnumber(L, (lua_Number)args->argv[i].i);
872  lua_rawseti(L, -2, i+1);
873  /*@switchbreak@*/ break;
874  case 'f':
875  lua_pushnumber(L, (lua_Number)args->argv[i].f);
876  lua_rawseti(L, -2, i+1);
877  /*@switchbreak@*/ break;
878  case 'p':
879  lua_pushlightuserdata(L, args->argv[i].p);
880  lua_rawseti(L, -2, i+1);
881  /*@switchbreak@*/ break;
882  default:
883  (void) luaL_error(L, "unsupported type '%c' as "
884  "a hook argument\n", args->argt[i]);
885  /*@switchbreak@*/ break;
886  }
887  }
888  if (lua_pcall(L, 1, 1, 0) != 0) {
889  rpmlog(RPMLOG_ERR, _("lua hook failed: %s\n"),
890  lua_tostring(L, -1));
891  lua_pop(L, 1);
892  } else {
893  if (lua_isnumber(L, -1))
894  ret = (int)lua_tonumber(L, -1);
895  lua_pop(L, 1);
896  }
897  return ret;
898 }
899 
900 static int rpm_register(lua_State *L)
901  /*@globals internalState @*/
902  /*@modifies L, internalState @*/
903 {
904  if (!lua_isstring(L, 1)) {
905  (void) luaL_argerror(L, 1, "hook name expected");
906  } else if (!lua_isfunction(L, 2)) {
907  (void) luaL_argerror(L, 2, "function expected");
908  } else {
909  rpmluaHookData hookdata =
910  lua_newuserdata(L, sizeof(struct rpmluaHookData_s));
911  lua_pushvalue(L, -1);
912  hookdata->dataRef = luaL_ref(L, LUA_REGISTRYINDEX);
913  lua_pushvalue(L, 2);
914  hookdata->funcRef = luaL_ref(L, LUA_REGISTRYINDEX);
915 /*@-temptrans@*/
916  hookdata->L = L;
917 /*@=temptrans@*/
918  rpmhookRegister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
919  return 1;
920  }
921  return 0;
922 }
923 
924 static int rpm_unregister(lua_State *L)
925  /*@modifies L @*/
926 {
927  if (!lua_isstring(L, 1)) {
928  (void) luaL_argerror(L, 1, "hook name expected");
929  } else if (!lua_islightuserdata(L, 2)) {
930  (void) luaL_argerror(L, 2, "hook information expected");
931  } else {
932  rpmluaHookData hookdata = (rpmluaHookData)lua_touserdata(L, 2);
933  luaL_unref(L, LUA_REGISTRYINDEX, hookdata->funcRef);
934  luaL_unref(L, LUA_REGISTRYINDEX, hookdata->dataRef);
935  rpmhookUnregister(lua_tostring(L, 1), rpmluaHookWrapper, hookdata);
936  }
937  return 0;
938 }
939 
940 static int rpm_call(lua_State *L)
941  /*@globals internalState @*/
942  /*@modifies L, internalState @*/
943 {
944  if (!lua_isstring(L, 1)) {
945  (void) luaL_argerror(L, 1, "hook name expected");
946  } else {
947  rpmhookArgs args = rpmhookArgsNew(lua_gettop(L)-1);
948  const char *name = lua_tostring(L, 1);
949  char *argt = (char *)xmalloc(args->argc+1);
950  int i;
951  for (i = 0; i != args->argc; i++) {
952  switch (lua_type(L, i+1)) {
953  case LUA_TNIL:
954  argt[i] = 'p';
955  args->argv[i].p = NULL;
956  /*@switchbreak@*/ break;
957  case LUA_TNUMBER: {
958  float f = (float)lua_tonumber(L, i+1);
959 /*@+relaxtypes@*/
960  if (f == (int)f) {
961  argt[i] = 'i';
962  args->argv[i].i = (int)f;
963  } else {
964  argt[i] = 'f';
965  args->argv[i].f = f;
966  }
967 /*@=relaxtypes@*/
968  } /*@switchbreak@*/ break;
969  case LUA_TSTRING:
970  argt[i] = 's';
971  args->argv[i].s = lua_tostring(L, i+1);
972  /*@switchbreak@*/ break;
973  case LUA_TUSERDATA:
974  case LUA_TLIGHTUSERDATA:
975  argt[i] = 'p';
976  args->argv[i].p = lua_touserdata(L, i+1);
977  /*@switchbreak@*/ break;
978  default:
979  (void) luaL_error(L, "unsupported Lua type passed to hook");
980  argt[i] = 'p';
981  args->argv[i].p = NULL;
982  /*@switchbreak@*/ break;
983  }
984  }
985 /*@-compdef -kepttrans -usereleased @*/
986  args->argt = argt;
987  rpmhookCallArgs(name, args);
988  argt = _free(argt);
989  (void) rpmhookArgsFree(args);
990 /*@=compdef =kepttrans =usereleased @*/
991  }
992  return 0;
993 }
994 
995 /* Based on luaB_print. */
996 static int rpm_print (lua_State *L)
997  /*@globals fileSystem @*/
998  /*@modifies L, fileSystem @*/
999 {
1000  rpmlua lua = (rpmlua)getdata(L, "lua");
1001  int n = lua_gettop(L); /* number of arguments */
1002  int i;
1003  if (!lua) return 0;
1004  lua_getglobal(L, "tostring");
1005  for (i = 1; i <= n; i++) {
1006  const char *s;
1007  lua_pushvalue(L, -1); /* function to be called */
1008  lua_pushvalue(L, i); /* value to print */
1009  lua_call(L, 1, 1);
1010  s = lua_tostring(L, -1); /* get result */
1011  if (s == NULL)
1012  return luaL_error(L, "`tostring' must return a string to `print'");
1013  if (lua->storeprint) {
1014  size_t sl = lua_strlen(L, -1);
1015  if ((size_t)(lua->printbufused+sl+1) > lua->printbufsize) {
1016  lua->printbufsize += sl+512;
1017  lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
1018  }
1019  if (i > 1)
1020  lua->printbuf[lua->printbufused++] = '\t';
1021  memcpy(lua->printbuf+lua->printbufused, s, sl+1);
1022  lua->printbufused += sl;
1023  } else {
1024  if (i > 1)
1025  (void) fputs("\t", stdout);
1026  (void) fputs(s, stdout);
1027  }
1028  lua_pop(L, 1); /* pop result */
1029  }
1030  if (!lua->storeprint) {
1031  (void) fputs("\n", stdout);
1032  } else {
1033  if ((size_t)(lua->printbufused+1) > lua->printbufsize) {
1034  lua->printbufsize += 512;
1035  lua->printbuf = xrealloc(lua->printbuf, lua->printbufsize);
1036  }
1037  lua->printbuf[lua->printbufused] = '\0';
1038  }
1039  return 0;
1040 }
1041 
1042 static int rpm_source(lua_State *L)
1043  /*@globals fileSystem, internalState @*/
1044  /*@modifies L, fileSystem, internalState @*/
1045 {
1046  if (!lua_isstring(L, 1)) {
1047  (void)luaL_argerror(L, 1, "filename expected");
1048  } else {
1049  rpmlua lua = (rpmlua)getdata(L, "lua");
1050  const char *filename = lua_tostring(L, 1);
1051  (void)rpmluaRunScriptFile(lua, filename);
1052  }
1053  return 0;
1054 }
1055 
1056 static int rpm_load(lua_State *L)
1057  /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1058  /*@modifies L, rpmGlobalMacroContext, fileSystem, internalState @*/
1059 {
1060  if (!lua_isstring(L, 1)) {
1061  (void)luaL_argerror(L, 1, "filename expected");
1062  } else {
1063  const char *filename = lua_tostring(L, 1);
1064 /*@-globs@*/
1065  (void)rpmLoadMacroFile(NULL, filename);
1066 /*@=globs@*/
1067  }
1068  return 0;
1069 }
1070 
1071 static int rpm_verbose(lua_State *L)
1072  /*@globals internalState @*/
1073  /*@modifies L, internalState @*/
1074 {
1075  lua_pushboolean(L, rpmIsVerbose());
1076  return 1;
1077 }
1078 
1079 static int rpm_debug(lua_State *L)
1080  /*@globals internalState @*/
1081  /*@modifies L, internalState @*/
1082 {
1083  lua_pushboolean(L, rpmIsDebug());
1084  return 1;
1085 }
1086 
1087 static int rpm_slurp(lua_State *L)
1088  /*@globals fileSystem, internalState @*/
1089  /*@modifies L, fileSystem, internalState @*/
1090 {
1091  rpmiob iob = NULL;
1092  const char *fn;
1093  int rc;
1094 
1095  if (lua_isstring(L, 1))
1096  fn = lua_tostring(L, 1);
1097  else {
1098  (void)luaL_argerror(L, 1, "filename");
1099  return 0;
1100  }
1101 /*@-globs@*/
1102  rc = rpmiobSlurp(fn, &iob);
1103 /*@=globs@*/
1104  if (rc || iob == NULL) {
1105  (void)luaL_error(L, "failed to slurp data");
1106  return 0;
1107  }
1108  lua_pushlstring(L, (const char *)rpmiobStr(iob), rpmiobLen(iob));
1109  iob = rpmiobFree(iob);
1110  return 1;
1111 }
1112 
1113 static int rpm_sleep(lua_State *L)
1114  /*@globals fileSystem, internalState @*/
1115  /*@modifies L, fileSystem, internalState @*/
1116 {
1117  unsigned sec;
1118 
1119  if (lua_isnumber(L, 1))
1120  sec = (unsigned) lua_tonumber(L, 1);
1121  else {
1122  (void)luaL_argerror(L, 1, "seconds");
1123  return 0;
1124  }
1125  (void) sleep(sec);
1126  return 0;
1127 }
1128 
1129 static int rpm_realpath(lua_State *L)
1130  /*@globals fileSystem, internalState @*/
1131  /*@modifies L, fileSystem, internalState @*/
1132 {
1133  const char *pn;
1134  char rp_buf[PATH_MAX];
1135  char *rp = "";
1136 
1137  if (lua_isstring(L, 1))
1138  pn = lua_tostring(L, 1);
1139  else {
1140  (void)luaL_argerror(L, 1, "pathname");
1141  return 0;
1142  }
1143  if ((rp = Realpath(pn, rp_buf)) == NULL) {
1144  (void)luaL_error(L, "failed to resolve path via realpath(3): %s", strerror(errno));
1145  return 0;
1146  }
1147  lua_pushstring(L, (const char *)rp);
1148  return 1;
1149 }
1150 
1151 static int rpm_hostname(lua_State *L)
1152  /*@globals h_errno, internalState @*/
1153  /*@modifies L, h_errno, internalState @*/
1154 {
1155  char hostname[1024];
1156  struct hostent *hbn;
1157  char *h;
1158 
1159 /*@-multithreaded@*/
1160  (void)gethostname(hostname, sizeof(hostname));
1161  if ((hbn = gethostbyname(hostname)) != NULL)
1162  h = hbn->h_name;
1163  else
1164  h = hostname;
1165 /*@=multithreaded@*/
1166  lua_pushstring(L, (const char *)h);
1167  return 1;
1168 }
1169 
1170 /*@-readonlytrans -nullassign @*/
1171 /*@observer@*/ /*@unchecked@*/
1172 static const luaL_reg rpmlib[] = {
1173  {"macros", rpm_macros},
1174  {"expand", rpm_expand},
1175  {"define", rpm_define},
1176  {"undefine", rpm_undefine},
1177  {"register", rpm_register},
1178  {"unregister", rpm_unregister},
1179  {"call", rpm_call},
1180  {"interactive", rpm_interactive},
1181  {"source", rpm_source},
1182  {"load", rpm_load},
1183  {"verbose", rpm_verbose},
1184  {"debug", rpm_debug},
1185  {"slurp", rpm_slurp},
1186  {"sleep", rpm_sleep},
1187  {"realpath", rpm_realpath},
1188  {"hostname", rpm_hostname},
1189  {NULL, NULL}
1190 };
1191 /*@=readonlytrans =nullassign @*/
1192 
1193 static int luaopen_rpm(lua_State *L)
1194  /*@modifies L @*/
1195 {
1196  lua_pushvalue(L, LUA_GLOBALSINDEX);
1197  luaL_openlib(L, "rpm", rpmlib, 0);
1198  return 0;
1199 }
1200 #endif /* WITH_LUA */
1201 
1202 /*@=moduncon =mustmod =realcompare =sizeoftype @*/