74cd41d70fe695c905e929e40b738d191fdfc5a4
[collectd.git] / src / lua.c
1 /**
2  * collectd - src/lua.c
3  * Copyright (C) 2010       Julien Ammous
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; only version 2.1 of the License is
8  * applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors:
20  *   Julien Ammous
21  **/
22
23 #include "collectd.h"
24 #include "plugin.h"
25 #include "common.h"
26 #include "configfile.h"
27 #include "utils_cache.h"
28
29 /* Include the Lua API header files. */
30 #include <lua.h>
31 #include <lauxlib.h>
32 #include <lualib.h>
33
34 #include "lua_exports.c"
35
36 typedef struct lua_script_s {
37   char          *script_path;
38   lua_State     *lua_state;
39   
40   struct lua_script_s  *next;
41 } lua_script_t;
42
43 static char           base_path[PATH_MAX + 1] = "";
44 static lua_script_t  *scripts = NULL;
45
46 /* Declare the Lua libraries we wish to use.
47  * Note: If you are opening and running a file containing Lua code using
48  * 'lua_dofile(l, "myfile.lua") - you must delcare all the libraries used in
49  * that file here also. */
50 static const luaL_reg lua_load_libs[] =
51 {
52 #if COLLECT_DEBUG
53   { LUA_DBLIBNAME,   luaopen_debug  },
54 #endif
55   { LUA_TABLIBNAME,  luaopen_table  },
56   { LUA_IOLIBNAME,   luaopen_io     },
57   { LUA_STRLIBNAME,  luaopen_string },
58   { LUA_MATHLIBNAME, luaopen_math   }
59 };
60
61 static void lua_script_free (lua_script_t *script) /* {{{ */
62 {
63   lua_script_t *next;
64
65   if (script == NULL)
66     return;
67
68   next = script->next;
69
70   if (script->lua_state != NULL)
71   {
72     lua_close (script->lua_state);
73     script->lua_state = NULL;
74   }
75
76   sfree (script->script_path);
77   sfree (script);
78
79   lua_script_free (next);
80 } /* }}} void lua_script_free */
81
82 static int lua_script_init (lua_script_t *script) /* {{{ */
83 {
84   size_t i;
85
86   memset (script, 0, sizeof (*script));
87   script->script_path = NULL;
88   script->next = NULL;
89
90   /* initialize the lua context */
91   script->lua_state = lua_open();
92   if (script->lua_state == NULL)
93   {
94     ERROR ("lua plugin: lua_open failed.");
95     return (-1);
96   }
97
98   /* Open up all the Lua libraries declared above. */
99   for (i = 0; i < STATIC_ARRAY_SIZE (lua_load_libs); i++)
100   {
101     int status;
102
103     status = (*lua_load_libs[i].func) (script->lua_state);
104     if (status != 0)
105       WARNING ("lua plugin: Loading library \"%s\" failed.",
106           lua_load_libs[i].name);
107   }
108
109   /* Register all the functions we implement in C */
110   register_exported_functions (script->lua_state);
111
112   return (0);
113 } /* }}} int lua_script_init */
114
115 static int lua_script_load (const char *script_path) /* {{{ */
116 {
117   lua_script_t *script;
118   int status;
119
120   script = malloc (sizeof (*script));
121   if (script == NULL)
122   {
123     ERROR ("lua plugin: malloc failed.");
124     return (-1);
125   }
126
127   status = lua_script_init (script);
128   if (status != 0)
129   {
130     lua_script_free (script);
131     return (status);
132   }
133
134   script->script_path = strdup (script_path);
135   if (script->script_path == NULL)
136   {
137     ERROR ("lua plugin: strdup failed.");
138     lua_script_free (script);
139     return (-1);
140   }
141
142   status = luaL_loadfile (script->lua_state, script->script_path);
143   if (status != 0)
144   {
145     const char *errmsg;
146
147     switch (status)
148     {
149       case LUA_ERRSYNTAX: errmsg = "Syntax error"; break;
150       case LUA_ERRFILE:   errmsg = "File I/O error"; break;
151       case LUA_ERRMEM:    errmsg = "Memory allocation error"; break;
152       default:            errmsg = "Unexpected error";
153     }
154
155     ERROR ("lua plugin: Loading script \"%s\" failed: %s",
156         script->script_path, errmsg);
157
158     lua_script_free (script);
159     return (-1);
160   }
161
162   /* Append this script to the global list of scripts. */
163   if (scripts == NULL)
164   {
165     scripts = script;
166   }
167   else
168   {
169     lua_script_t *last;
170
171     last = scripts;
172     while (last->next != NULL)
173       last = last->next;
174
175     last->next = script;
176   }
177
178   return (0);
179 } /* }}} int lua_script_load */
180
181 static int lua_config_base_path (const oconfig_item_t *ci) /* {{{ */
182 {
183   int status;
184   size_t len;
185
186   status = cf_util_get_string_buffer (ci, base_path, sizeof (base_path));
187   if (status != 0)
188     return (status);
189
190   len = strlen (base_path);
191   while ((len > 0) && (base_path[len - 1] == '/'))
192   {
193     len--;
194     base_path[len] = 0;
195   }
196
197   DEBUG ("lua plugin: base_path = \"%s\";", base_path);
198
199   return (0);
200 } /* }}} int lua_config_base_path */
201
202 static int lua_config_script (const oconfig_item_t *ci) /* {{{ */
203 {
204   char rel_path[PATH_MAX + 1];
205   char abs_path[PATH_MAX + 1];
206   int status;
207
208   status = cf_util_get_string_buffer (ci, rel_path, sizeof (rel_path));
209   if (status != 0)
210     return (status);
211
212   if (base_path[0] == 0)
213     sstrncpy (abs_path, rel_path, sizeof (abs_path));
214   else
215     ssnprintf (abs_path, sizeof (abs_path), "%s/%s", base_path, rel_path);
216
217   DEBUG ("lua plugin: abs_path = \"%s\";", abs_path);
218
219   status = lua_script_load (abs_path);
220   if (status != 0)
221     return (status);
222
223   INFO("lua plugin: File \"%s\" loaded succesfully", abs_path);
224   
225   return 0;
226 } /* }}} int lua_config_script */
227
228 /*
229  * <Plugin lua>
230  *   BasePath "/"
231  *   Script "script1.lua"
232  *   Script "script2.lua"
233  * </Plugin>
234  */
235 static int lua_config (oconfig_item_t *ci) /* {{{ */
236 {
237   int i;
238
239   for (i = 0; i < ci->children_num; i++)
240   {
241     oconfig_item_t *child = ci->children + i;
242
243     if (strcasecmp ("BasePath", child->key) == 0) {
244       lua_config_base_path(child);
245     }
246     else if (strcasecmp ("Script", child->key) == 0){
247       lua_config_script(child);
248     }
249     else
250     {
251       WARNING ("network plugin: Option `%s' is not allowed here.",
252           child->key);
253     }
254   }
255   
256   return 0;
257 } /* }}} int lua_config */
258
259 static int lua_shutdown (void) /* {{{ */
260 {
261   lua_script_free (scripts);
262   scripts = NULL;
263
264   return (0);
265 } /* }}} int lua_shutdown */
266
267 void module_register()
268 {
269   plugin_register_complex_config("lua", lua_config);
270   plugin_register_shutdown("lua", lua_shutdown);
271 }
272
273 /* vim: set sw=2 sts=2 et fdm=marker : */