dlua-script.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "lib.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "llist.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "istream.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "sha1.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "hex-binary.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "eacces-error.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include "dlua-script-private.h"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include <fcntl.h>
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#include <unistd.h>
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#define LUA_SCRIPT_INIT_FN "script_init"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#define LUA_SCRIPT_DEINIT_FN "script_deinit"
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic struct dlua_script *dlua_scripts = NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic const char *dlua_errstr(int err)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi switch(err) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#ifdef LUA_OK
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_OK:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "ok";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#endif
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_YIELD:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "yield";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRRUN:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "runtime error";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRSYNTAX:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "syntax error";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRMEM:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "out of memory";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#ifdef LUA_ERRGCMM
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRGCMM:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "gc management error";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#endif
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRERR:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "error while handling error";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#ifdef LUA_ERRFILE
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case LUA_ERRFILE:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "error loading file";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi#endif
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi default:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return "unknown error";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic void *dlua_alloc(void *ctx, void *ptr, size_t osize, size_t nsize)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script =
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi (struct dlua_script*)ctx;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (nsize == 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi p_free(script->pool, ptr);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi } else {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return p_realloc(script->pool, ptr, osize, nsize);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic const char *dlua_reader(lua_State *L, void *ctx, size_t *size_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script =
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi (struct dlua_script*)ctx;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const unsigned char *data;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_stream_skip(script->in, script->last_read);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (i_stream_read_more(script->in, &data, size_r) == -1 &&
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->in->stream_errno != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi luaL_error(L, t_strdup_printf("read(%s) failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->filename,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_stream_get_error(script->in)));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *size_r = 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->last_read = *size_r;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return (const char*)data;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistruct dlua_script *dlua_script_from_state(lua_State *L)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi for(script = dlua_scripts; script != NULL; script = script->next)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (script->L == L)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_unreached();
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomiint dlua_script_init(struct dlua_script *script, const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int ret = 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (script->init)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->init = TRUE;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* see if there is a symbol for init */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_getglobal(script->L, LUA_SCRIPT_INIT_FN);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (lua_isfunction(script->L, -1)) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi ret = lua_pcall(script->L, 0, 1, 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (ret != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("lua_pcall("LUA_SCRIPT_INIT_FN") failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_tostring(script->L, -1));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi ret = -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi } else if (lua_isnumber(script->L, -1)) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi ret = lua_tointeger(script->L, -1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (ret != 0)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = "Script init failed";
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi } else {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf(LUA_SCRIPT_INIT_FN "() returned non-number");
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi ret = -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pop(script->L, 1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return ret;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic struct dlua_script *dlua_create_script(const char *name)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi pool_t pool = pool_allocfree_create(t_strdup_printf("lua script %s", name));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script = p_new(pool, struct dlua_script, 1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->pool = pool;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->filename = p_strdup(pool, name);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* lua API says that lua_newstate will return NULL only if it's out of
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi memory. this cannot really happen with our allocator as it will
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi call i_fatal_status anyways if it runs out of memory */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->L = lua_newstate(dlua_alloc, script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(script->L != NULL);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->ref = 1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi luaL_openlibs(script->L);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic int dlua_run_script(struct dlua_script *script, const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int err = lua_pcall(script->L, 0, 0, 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (err != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("lua_pcall(%s) failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->filename,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_tostring(script->L, -1));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pop(script->L,1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic struct dlua_script *
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomidlua_script_find_previous_script(const char *filename)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi for(script = dlua_scripts; script != NULL; script = script->next)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (strcmp(script->filename, filename)==0)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic int
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomidlua_script_create_finish(struct dlua_script *script, struct dlua_script **script_r,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (dlua_run_script(script, error_r) < 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_unref(&script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi DLLIST_PREPEND(&dlua_scripts, script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *script_r = script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomiint dlua_script_create_string(const char *str, struct dlua_script **script_r,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int err;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi unsigned char scripthash[SHA1_RESULTLEN];
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char *fn;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *script_r = NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi sha1_get_digest(str, strlen(str), scripthash);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi fn = binary_to_hex(scripthash, sizeof(scripthash));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((script = dlua_script_find_previous_script(fn)) != NULL) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_ref(script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *script_r = script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script = dlua_create_script(fn);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((err = luaL_loadstring(script->L, str)) != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("lua_load(<string>) failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_errstr(err));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_unref(&script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return dlua_script_create_finish(script, script_r, error_r);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomiint dlua_script_create_file(const char *file, struct dlua_script **script_r,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int err;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((script = dlua_script_find_previous_script(file)) != NULL) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_ref(script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *script_r = script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* lua reports file access errors poorly */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (access(file, O_RDONLY) < 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (errno == EACCES)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = eacces_error_get("access", file);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi else
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("access(%s) failed: %m",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi file);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script = dlua_create_script(file);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((err = luaL_loadfile(script->L, file)) != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("lua_load(%s) failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi file, dlua_errstr(err));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_unref(&script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return dlua_script_create_finish(script, script_r, error_r);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomiint dlua_script_create_stream(struct istream *is, struct dlua_script **script_r,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char **error_r)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const char *filename = i_stream_get_name(is);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int err;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(filename != NULL && *filename != '\0');
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((script = dlua_script_find_previous_script(filename)) != NULL) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_ref(script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *script_r = script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return 0;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script = dlua_create_script(filename);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->in = is;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->filename = p_strdup(script->pool, filename);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if ((err = lua_load(script->L, dlua_reader, script, filename, 0)) < 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *error_r = t_strdup_printf("lua_load(%s) failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi filename, dlua_errstr(err));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_unref(&script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return -1;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return dlua_script_create_finish(script, script_r, error_r);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomistatic void dlua_script_destroy(struct dlua_script *script)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* courtesy call */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi int ret;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* see if there is a symbol for deinit */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_getglobal(script->L, LUA_SCRIPT_DEINIT_FN);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (lua_isfunction(script->L, -1)) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi ret = lua_pcall(script->L, 0, 0, 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (ret != 0) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_warning("lua_pcall("LUA_SCRIPT_DEINIT_FN") failed: %s",
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_tostring(script->L, -1));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pop(script->L, 1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi } else {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pop(script->L, 1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_close(script->L);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi /* then just release memory */
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi pool_unref(&script->pool);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomivoid dlua_script_ref(struct dlua_script *script)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(script->ref > 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi script->ref++;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomivoid dlua_script_unref(struct dlua_script **_script)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi struct dlua_script *script = *_script;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi *_script = NULL;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (script == NULL) return;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(script->ref > 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi if (--script->ref > 0)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi dlua_script_destroy(script);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomibool dlua_script_has_function(struct dlua_script *script, const char *fn)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(script != NULL);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_getglobal(script->L, fn);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi bool ret = lua_isfunction(script->L, -1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pop(script->L, 1);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi return ret;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomivoid dlua_setmembers(struct dlua_script *script,
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi const struct dlua_table_values *values, int idx)
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi{
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(script != NULL);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_assert(lua_istable(script->L, idx));
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi while(values->name != NULL) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi switch(values->type) {
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case DLUA_TABLE_VALUE_STRING:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pushstring(script->L, values->v.s);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi break;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case DLUA_TABLE_VALUE_INTEGER:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pushnumber(script->L, values->v.i);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi break;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case DLUA_TABLE_VALUE_DOUBLE:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pushnumber(script->L, values->v.d);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi break;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case DLUA_TABLE_VALUE_BOOLEAN:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pushboolean(script->L, values->v.b ? 1 : 0);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi break;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi case DLUA_TABLE_VALUE_NULL:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_pushnil(script->L);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi break;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi default:
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi i_unreached();
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi lua_setfield(script->L, idx-1, values->name);
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi values++;
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi }
e88e76e782853e826d00524ee1133e64fb69b3d9Aki Tuomi}