rpm 5.2.1

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

- File List
- Globals

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@*/
56 rpmioPool _rpmluaPool = NULL;
57
58 /*@unchecked@*/ /*@only@*/ /*@null@*/
59 rpmioPool _rpmluavPool = 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
94 rpmlua rpmluaGetGlobalState(void)
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) {
635 rpmlog(RPMLOG_ERR,
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 @*/