Fix compile time issues
[collectd.git] / src / lua.c
index 2bd56a1..3f48a55 100644 (file)
--- a/src/lua.c
+++ b/src/lua.c
  *   Ruben Kerkhof <ruben at rubenkerkhof.com>
  **/
 
-/* <lua5.1/luaconf.h> defines a macro using "sprintf". Although not used here,
- * GCC will complain about the macro definition. */
-#define DONT_POISON_SPRINTF_YET
-
-#include "common.h"
-#include "plugin.h"
 #include "collectd.h"
+#include "plugin.h"
+#include "utils/common/common.h"
+#include "utils_lua.h"
 
 /* Include the Lua API header files. */
 #include <lauxlib.h>
 #include <lua.h>
 #include <lualib.h>
-#include "utils_lua.h"
 
 #include <pthread.h>
 
-#if COLLECT_DEBUG && __GNUC__
-#undef sprintf
-#pragma GCC poison sprintf
-#endif
+#define PLUGIN_READ 1
+#define PLUGIN_WRITE 2
 
 typedef struct lua_script_s {
-  char *script_path;
   lua_State *lua_state;
   struct lua_script_s *next;
 } lua_script_t;
 
 typedef struct {
   lua_State *lua_state;
-  const char *lua_function_name;
+  char *lua_function_name;
   pthread_mutex_t lock;
   int callback_id;
 } clua_callback_data_t;
@@ -79,29 +72,25 @@ static int clua_load_callback(lua_State *L, int callback_ref) /* {{{ */
 
   if (!lua_isfunction(L, -1)) {
     lua_pop(L, 1);
-    return (-1);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int clua_load_callback */
 
 /* Store the threads in a global variable so they are not cleaned up by the
  * garbage collector. */
 static int clua_store_thread(lua_State *L, int idx) /* {{{ */
 {
-  if (idx < 0)
-    idx += lua_gettop(L) + 1;
+  if (!lua_isthread(L, idx)) {
+    return -1;
+  }
 
   /* Copy the thread pointer */
-  lua_pushvalue(L, idx); /* +1 = 3 */
-  if (!lua_isthread(L, -1)) {
-    lua_pop(L, 3); /* -3 = 0 */
-    return (-1);
-  }
+  lua_pushvalue(L, idx);
 
   luaL_ref(L, LUA_REGISTRYINDEX);
-  lua_pop(L, 1); /* -1 = 0 */
-  return (0);
+  return 0;
 } /* }}} int clua_store_thread */
 
 static int clua_read(user_data_t *ud) /* {{{ */
@@ -117,7 +106,7 @@ static int clua_read(user_data_t *ud) /* {{{ */
     ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
           cb->lua_function_name, cb->callback_id);
     pthread_mutex_unlock(&cb->lock);
-    return (-1);
+    return -1;
   }
   /* +1 = 1 */
 
@@ -131,7 +120,7 @@ static int clua_read(user_data_t *ud) /* {{{ */
       ERROR("Lua plugin: Calling a read callback failed: %s", errmsg);
     lua_pop(L, 1);
     pthread_mutex_unlock(&cb->lock);
-    return (-1);
+    return -1;
   }
 
   if (!lua_isnumber(L, -1)) {
@@ -147,7 +136,7 @@ static int clua_read(user_data_t *ud) /* {{{ */
   lua_pop(L, 1); /* -1 = 0 */
 
   pthread_mutex_unlock(&cb->lock);
-  return (status);
+  return status;
 } /* }}} int clua_read */
 
 static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
@@ -163,7 +152,7 @@ static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
     ERROR("Lua plugin: Unable to load callback \"%s\" (id %i).",
           cb->lua_function_name, cb->callback_id);
     pthread_mutex_unlock(&cb->lock);
-    return (-1);
+    return -1;
   }
   /* +1 = 1 */
 
@@ -172,7 +161,7 @@ static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
     lua_pop(L, 1); /* -1 = 0 */
     pthread_mutex_unlock(&cb->lock);
     ERROR("Lua plugin: luaC_pushvaluelist failed.");
-    return (-1);
+    return -1;
   }
   /* +1 = 2 */
 
@@ -186,7 +175,7 @@ static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
       ERROR("Lua plugin: Calling the write callback failed:\n%s", errmsg);
     lua_pop(L, 1); /* -1 = 0 */
     pthread_mutex_unlock(&cb->lock);
-    return (-1);
+    return -1;
   }
 
   if (!lua_isnumber(L, -1)) {
@@ -200,7 +189,7 @@ static int clua_write(const data_set_t *ds, const value_list_t *vl, /* {{{ */
 
   lua_pop(L, 1); /* -1 = 0 */
   pthread_mutex_unlock(&cb->lock);
-  return (status);
+  return status;
 } /* }}} int clua_write */
 
 /*
@@ -272,60 +261,46 @@ static int lua_cb_dispatch_values(lua_State *L) /* {{{ */
   return 0;
 } /* }}} lua_cb_dispatch_values */
 
-static int lua_cb_register_read(lua_State *L) /* {{{ */
+static void lua_cb_free(void *data) {
+  clua_callback_data_t *cb = data;
+  free(cb->lua_function_name);
+  pthread_mutex_destroy(&cb->lock);
+  free(cb);
+}
+
+static int lua_cb_register_generic(lua_State *L, int type) /* {{{ */
 {
   int nargs = lua_gettop(L);
 
   if (nargs != 1)
     return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
 
-  luaL_checktype(L, 1, LUA_TFUNCTION);
-
-  char function_name[DATA_MAX_NAME_LEN];
-  ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
-
-  int callback_id = clua_store_callback(L, 1);
-  if (callback_id < 0)
-    return luaL_error(L, "%s", "Storing callback function failed");
-
-  lua_State *thread = lua_newthread(L);
-  if (thread == NULL)
-    return luaL_error(L, "%s", "lua_newthread failed");
-  clua_store_thread(L, -1);
-  lua_pop(L, 1);
-
-  clua_callback_data_t *cb = calloc(1, sizeof(*cb));
-  if (cb == NULL)
-    return luaL_error(L, "%s", "calloc failed");
-
-  cb->lua_state = thread;
-  cb->callback_id = callback_id;
-  cb->lua_function_name = strdup(function_name);
-  pthread_mutex_init(&cb->lock, NULL);
-
-  int status = plugin_register_complex_read(/* group = */ "lua",
-                                            /* name      = */ function_name,
-                                            /* callback  = */ clua_read,
-                                            /* interval  = */ 0, &(user_data_t){
-                                                                     .data = cb,
-                                                                 });
-
-  if (status != 0)
-    return luaL_error(L, "%s", "plugin_register_complex_read failed");
-  return 0;
-} /* }}} int lua_cb_register_read */
-
-static int lua_cb_register_write(lua_State *L) /* {{{ */
-{
-  int nargs = lua_gettop(L);
+  char subname[DATA_MAX_NAME_LEN];
+  if (!lua_isfunction(L, 1) && lua_isstring(L, 1)) {
+    const char *fname = lua_tostring(L, 1);
+    ssnprintf(subname, sizeof(subname), "%s()", fname);
 
-  if (nargs != 1)
-    return luaL_error(L, "Invalid number of arguments (%d != 1)", nargs);
+    lua_getglobal(L, fname); // Push function into stack
+    lua_remove(L, 1);        // Remove string from stack
+    if (!lua_isfunction(L, -1)) {
+      return luaL_error(L, "Unable to find function '%s'", fname);
+    }
+  } else {
+    lua_getfield(L, LUA_REGISTRYINDEX, "collectd:callback_num");
+    int tmp = lua_tointeger(L, -1);
+    ssnprintf(subname, sizeof(subname), "callback_%d", tmp);
+    lua_pop(L, 1); // Remove old value from stack
+    lua_pushinteger(L, tmp + 1);
+    lua_setfield(L, LUA_REGISTRYINDEX, "collectd:callback_num"); // pops value
+  }
 
   luaL_checktype(L, 1, LUA_TFUNCTION);
 
-  char function_name[DATA_MAX_NAME_LEN] = "";
-  ssnprintf(function_name, sizeof(function_name), "lua/%s", lua_tostring(L, 1));
+  lua_getfield(L, LUA_REGISTRYINDEX, "collectd:script_path");
+  char function_name[DATA_MAX_NAME_LEN];
+  ssnprintf(function_name, sizeof(function_name), "lua/%s/%s",
+            lua_tostring(L, -1), subname);
+  lua_pop(L, 1);
 
   int callback_id = clua_store_callback(L, 1);
   if (callback_id < 0)
@@ -346,16 +321,42 @@ static int lua_cb_register_write(lua_State *L) /* {{{ */
   cb->lua_function_name = strdup(function_name);
   pthread_mutex_init(&cb->lock, NULL);
 
-  int status =
-      plugin_register_write(/* name = */ function_name,
-                            /* callback  = */ clua_write, &(user_data_t){
-                                                              .data = cb,
-                                                          });
+  if (PLUGIN_READ == type) {
+    int status = plugin_register_complex_read(/* group = */ "lua",
+                                              /* name      = */ function_name,
+                                              /* callback  = */ clua_read,
+                                              /* interval  = */ 0,
+                                              &(user_data_t){
+                                                  .data = cb,
+                                                  .free_func = lua_cb_free,
+                                              });
+
+    if (status != 0)
+      return luaL_error(L, "%s", "plugin_register_complex_read failed");
+    return 0;
+  } else if (PLUGIN_WRITE == type) {
+    int status = plugin_register_write(/* name = */ function_name,
+                                       /* callback  = */ clua_write,
+                                       &(user_data_t){
+                                           .data = cb,
+                                           .free_func = lua_cb_free,
+                                       });
+
+    if (status != 0)
+      return luaL_error(L, "%s", "plugin_register_write failed");
+    return 0;
+  } else {
+    return luaL_error(L, "%s", "lua_cb_register_generic unsupported type");
+  }
+} /* }}} int lua_cb_register_generic */
+
+static int lua_cb_register_read(lua_State *L) {
+  return lua_cb_register_generic(L, PLUGIN_READ);
+}
 
-  if (status != 0)
-    return luaL_error(L, "%s", "plugin_register_write failed");
-  return 0;
-} /* }}} int lua_cb_register_write */
+static int lua_cb_register_write(lua_State *L) {
+  return lua_cb_register_generic(L, PLUGIN_WRITE);
+}
 
 static const luaL_Reg collectdlib[] = {
     {"log_debug", lua_cb_log_debug},
@@ -390,7 +391,6 @@ static void lua_script_free(lua_script_t *script) /* {{{ */
     script->lua_state = NULL;
   }
 
-  sfree(script->script_path);
   sfree(script);
 
   lua_script_free(next);
@@ -404,7 +404,7 @@ static int lua_script_init(lua_script_t *script) /* {{{ */
   script->lua_state = luaL_newstate();
   if (script->lua_state == NULL) {
     ERROR("Lua plugin: luaL_newstate() failed.");
-    return (-1);
+    return -1;
   }
 
   /* Open up all the standard Lua libraries. */
@@ -437,7 +437,7 @@ static int lua_script_init(lua_script_t *script) /* {{{ */
     lua_pop(script->lua_state, 1);
   }
 
-  return (0);
+  return 0;
 } /* }}} int lua_script_init */
 
 static int lua_script_load(const char *script_path) /* {{{ */
@@ -445,31 +445,29 @@ static int lua_script_load(const char *script_path) /* {{{ */
   lua_script_t *script = malloc(sizeof(*script));
   if (script == NULL) {
     ERROR("Lua plugin: malloc failed.");
-    return (-1);
+    return -1;
   }
 
   int status = lua_script_init(script);
   if (status != 0) {
     lua_script_free(script);
-    return (status);
-  }
-
-  script->script_path = strdup(script_path);
-  if (script->script_path == NULL) {
-    ERROR("Lua plugin: strdup failed.");
-    lua_script_free(script);
-    return (-1);
+    return status;
   }
 
-  status = luaL_loadfile(script->lua_state, script->script_path);
+  status = luaL_loadfile(script->lua_state, script_path);
   if (status != 0) {
     ERROR("Lua plugin: luaL_loadfile failed: %s",
           lua_tostring(script->lua_state, -1));
     lua_pop(script->lua_state, 1);
     lua_script_free(script);
-    return (-1);
+    return -1;
   }
 
+  lua_pushstring(script->lua_state, script_path);
+  lua_setfield(script->lua_state, LUA_REGISTRYINDEX, "collectd:script_path");
+  lua_pushinteger(script->lua_state, 0);
+  lua_setfield(script->lua_state, LUA_REGISTRYINDEX, "collectd:callback_num");
+
   status = lua_pcall(script->lua_state,
                      /* nargs = */ 0,
                      /* nresults = */ LUA_MULTRET,
@@ -482,11 +480,8 @@ static int lua_script_load(const char *script_path) /* {{{ */
             "In addition, no error message could be retrieved from the stack.",
             status);
     else
-      ERROR("Lua plugin: Executing script \"%s\" failed:\n%s",
-            script->script_path, errmsg);
-
-    lua_script_free(script);
-    return (-1);
+      ERROR("Lua plugin: Executing script \"%s\" failed: %s", script_path,
+            errmsg);
   }
 
   /* Append this script to the global list of scripts. */
@@ -500,14 +495,17 @@ static int lua_script_load(const char *script_path) /* {{{ */
     scripts = script;
   }
 
-  return (0);
+  if (status != 0)
+    return -1;
+
+  return 0;
 } /* }}} int lua_script_load */
 
 static int lua_config_base_path(const oconfig_item_t *ci) /* {{{ */
 {
   int status = cf_util_get_string_buffer(ci, base_path, sizeof(base_path));
   if (status != 0)
-    return (status);
+    return status;
 
   size_t len = strlen(base_path);
   while ((len > 0) && (base_path[len - 1] == '/')) {
@@ -517,7 +515,7 @@ static int lua_config_base_path(const oconfig_item_t *ci) /* {{{ */
 
   DEBUG("Lua plugin: base_path = \"%s\";", base_path);
 
-  return (0);
+  return 0;
 } /* }}} int lua_config_base_path */
 
 static int lua_config_script(const oconfig_item_t *ci) /* {{{ */
@@ -526,7 +524,7 @@ static int lua_config_script(const oconfig_item_t *ci) /* {{{ */
 
   int status = cf_util_get_string_buffer(ci, rel_path, sizeof(rel_path));
   if (status != 0)
-    return (status);
+    return status;
 
   char abs_path[PATH_MAX];
 
@@ -539,7 +537,7 @@ static int lua_config_script(const oconfig_item_t *ci) /* {{{ */
 
   status = lua_script_load(abs_path);
   if (status != 0)
-    return (status);
+    return status;
 
   INFO("Lua plugin: File \"%s\" loaded successfully", abs_path);
 
@@ -576,12 +574,10 @@ static int lua_shutdown(void) /* {{{ */
 {
   lua_script_free(scripts);
 
-  return (0);
+  return 0;
 } /* }}} int lua_shutdown */
 
 void module_register(void) {
   plugin_register_complex_config("lua", lua_config);
   plugin_register_shutdown("lua", lua_shutdown);
 }
-
-/* vim: set sw=2 sts=2 et fdm=marker : */