The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
util.c
Go to the documentation of this file.
1 /*
2  * This program is is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License, version 2 if the
4  * License as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9  * GNU General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public License
12  * along with this program; if not, write to the Free Software
13  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
14  */
15 
16 /**
17  * $Id: 1d4c3ee70b185ee350bdf5a4c5faf9429ad53007 $
18  * @file rlm_lua/util.c
19  * @brief Helper Lua land functions.
20  *
21  * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22  *
23  * @copyright 2013 The FreeRADIUS Server Project.
24  */
25 RCSID("$Id: 1d4c3ee70b185ee350bdf5a4c5faf9429ad53007 $")
26 
27 #define LOG_PREFIX fr_lua_mctx->inst->name
28 
29 #include <freeradius-devel/server/base.h>
30 
31 #include "config.h"
32 #include "lua.h"
33 
34 #include <lauxlib.h>
35 #include <lualib.h>
36 
37 static _Thread_local request_t *fr_lua_request;
38 static _Thread_local module_ctx_t const *fr_lua_mctx;
39 
40 void fr_lua_util_fr_register(lua_State *L)
41 {
42  /* fr.{} */
43  lua_newtable(L);
44  lua_setglobal(L, "fr");
45  lua_settop(L, 0);
46 }
47 
48 /** Lua function to output debug messages
49  *
50  * Lua arguments are one or more strings. Each successive argument will be printed on a new line.
51  *
52  * @param L Lua interpreter.
53  * @return 0 (no arguments)
54  */
55 static int _util_log_debug(lua_State *L)
56 {
57  request_t *request = fr_lua_request;
58  int idx;
59 
60  while ((idx = lua_gettop(L))) {
61  char const *msg = lua_tostring(L, idx);
62  lua_pop(L, 1);
63  if (!msg) continue;
64 
65  ROPTIONAL(RDEBUG2, DEBUG2, "%s", msg);
66  }
67 
68  return 0;
69 }
70 
71 /** Lua function to output informational messages
72  *
73  * Lua arguments are one or more strings. Each successive argument will be printed on a new line.
74  *
75  * @param L Lua interpreter.
76  * @return 0 (no arguments)
77  */
78 static int _util_log_info(lua_State *L)
79 {
80  request_t *request = fr_lua_request;
81  int idx;
82 
83  while ((idx = lua_gettop(L))) {
84  char const *msg = lua_tostring(L, idx);
85  lua_pop(L, 1);
86  if (!msg) continue;
87 
88  ROPTIONAL(RINFO, INFO, "%s", msg);
89  }
90 
91  return 0;
92 }
93 
94 
95 /** Lua function to output warning messages
96  *
97  * Lua arguments are one or more strings. Each successive argument will be printed on a new line.
98  *
99  * @param L Lua interpreter.
100  * @return 0 (no arguments)
101  */
102 static int _util_log_warn(lua_State *L)
103 {
104  request_t *request = fr_lua_request;
105  int idx;
106 
107  while ((idx = lua_gettop(L))) {
108  char const *msg = lua_tostring(L, idx);
109  lua_pop(L, 1);
110  if (!msg) continue;
111 
112  ROPTIONAL(RWARN, WARN, "%s", msg);
113  }
114 
115  return 0;
116 }
117 
118 /** Lua function to output error messages.
119  *
120  * Lua arguments are one or more strings. Each successive argument will be printed on a new line.
121  *
122  * @param L Lua interpreter.
123  * @return 0 (no arguments)
124  */
125 static int _util_log_error(lua_State *L)
126 {
127  request_t *request = fr_lua_request;
128  int idx;
129 
130  while ((idx = lua_gettop(L))) {
131  char const *msg = lua_tostring(L, idx);
132  lua_pop(L, 1);
133  if (!msg) continue;
134 
135  ROPTIONAL(RERROR, ERROR, "%s", msg);
136  }
137 
138  return 0;
139 }
140 
141 static int _util_log_newindex(UNUSED lua_State *L)
142 {
143  request_t *request = fr_lua_util_get_request();
144 
145  RWDEBUG("fr.log.$func() is read-only");
146 
147  return 1;
148 }
149 
150 /** Emit a debug log message
151  *
152  * @param msg to be printed.
153  */
155 {
156  request_t *request = fr_lua_request;
157 
158  ROPTIONAL(RDEBUG2, DEBUG2, "%s", msg);
159 }
160 
161 /** Emit an info log message
162  *
163  * @param msg to be printed.
164  */
165 void fr_lua_util_jit_log_info(char const *msg)
166 {
167  request_t *request = fr_lua_request;
168 
169  ROPTIONAL(RINFO, INFO, "%s", msg);
170 }
171 
172 /** Emit a warning log message
173  *
174  * @param msg to be printed.
175  */
176 void fr_lua_util_jit_log_warn(char const *msg)
177 {
178  request_t *request = fr_lua_request;
179 
180  ROPTIONAL(RWARN, WARN, "%s", msg);
181 }
182 
183 /** Emit a error log message
184  *
185  * @param msg to be printed.
186  */
188 {
189  request_t *request = fr_lua_request;
190 
191  ROPTIONAL(RERROR, ERROR, "%s", msg);
192 }
193 
194 /** Insert cdefs into the lua environment
195  *
196  * For LuaJIT using the FFI is significantly faster than the Lua interface.
197  * Help people wishing to use the FFI by inserting cdefs for standard functions.
198  *
199  * @param L Lua interpreter.
200  * @return 0 (no arguments).
201  */
203 {
204  char const *search_path;
205  char *lua_str, *ctx = NULL;
206  int ret;
207 
209 
210  search_path = dl_module_search_path();
211 
212  /*
213  * If the search path contains multiple directories find where the library is.
214  */
215  if (strchr(search_path, ':')) {
216  char *paths, *path, *file, *p;
217  ctx = paths = talloc_typed_strdup(NULL, search_path);
218  while ((path = strsep(&paths, ":")) != NULL) {
219  p = strrchr(path, '/');
220  if (p && ((p[1] == '\0') || (p[1] == ':'))) *p = '\0';
221  file = talloc_typed_asprintf(ctx, "%s%clibfreeradius-lua%s", path, FR_DIR_SEP, DL_EXTENSION);
222  if (access(file, F_OK) == 0) {
223  search_path = path;
224  break;
225  }
226  }
227  }
228 
229  lua_str = talloc_asprintf(NULL, "\
230  ffi = require(\"ffi\")\
231  ffi.cdef [[\
232  void fr_lua_util_jit_log_debug(char const *msg);\
233  void fr_lua_util_jit_log_info(char const *msg);\
234  void fr_lua_util_jit_log_warn(char const *msg);\
235  void fr_lua_util_jit_log_error(char const *msg);\
236  ]]\
237  fr_lua = ffi.load(\"%s%clibfreeradius-lua%s\")\
238  _fr_log = {}\
239  _fr_log.debug = function(msg)\
240  fr_lua.fr_lua_util_jit_log_debug(msg)\
241  end\
242  _fr_log.info = function(msg)\
243  fr_lua.fr_lua_util_jit_log_info(msg)\
244  end\
245  _fr_log.warn = function(msg)\
246  fr_lua.fr_lua_util_jit_log_warn(msg)\
247  end\
248  _fr_log.error = function(msg)\
249  fr_lua.fr_lua_util_jit_log_error(msg)\
250  end\
251  function _ro_log(table) \
252  return setmetatable({}, { \
253  __index = table,\
254  __newindex = function(table, key, value)\
255  _fr_log.warn(\"fr.log.$func() is read-only\")\
256  end, \
257  __metatable = false \
258  }); \
259  end\
260  fr.log = _ro_log(_fr_log)\
261  ", search_path, FR_DIR_SEP, DL_EXTENSION);
262  ret = luaL_dostring(L, lua_str);
263  talloc_free(lua_str);
264  TALLOC_FREE(ctx);
265  if (ret != 0) {
266  ERROR("Failed setting up FFI: %s",
267  lua_gettop(L) ? lua_tostring(L, -1) : "Unknown error");
268 
269  return -1;
270  }
271 
272  return 0;
273 }
274 
275 /** Register utililiary functions in the lua environment
276  *
277  * @param L Lua interpreter.
278  * @return 0 (no arguments).
279  */
281 {
282  /* fr.{} */
283  lua_getglobal(L, "fr");
284  luaL_checktype(L, -1, LUA_TTABLE);
285 
286  /* fr.log.{} */
287  lua_newtable(L);
288  {
289  lua_newtable(L); //__metatable
290  {
291  lua_pushvalue(L, -1);
292  lua_setfield(L, -2, "__index");
293 
294  lua_pushcfunction(L, _util_log_newindex);
295  lua_setfield(L, -2, "__newindex");
296  }
297 
298  lua_pushcfunction(L, _util_log_debug);
299  lua_setfield(L, -2, "debug");
300 
301  lua_pushcfunction(L, _util_log_info);
302  lua_setfield(L, -2, "info");
303 
304  lua_pushcfunction(L, _util_log_warn);
305  lua_setfield(L, -2, "warn");
306 
307  lua_pushcfunction(L, _util_log_error);
308  lua_setfield(L, -2, "error");
309  }
310 
311  lua_setmetatable(L, -2);
312  lua_setfield(L, -2, "log");
313 
314  return 0;
315 }
316 
317 /** Set the thread local instance
318  *
319  * @param[in] mctx all helper and C functions callable from Lua should use.
320  */
322 {
323  fr_lua_mctx = mctx;
324 }
325 
326 /** Get the thread local instance
327  *
328  * @return mctx all helper and C functions callable from Lua should use.
329  */
331 {
332  return fr_lua_mctx;
333 }
334 
335 /** Set the thread local request
336  *
337  * @param[in] request all helper and C functions callable from Lua should use.
338  */
340 {
341  fr_lua_request = request;
342 }
343 
344 /** Get the thread local request
345  *
346  * @return request all helper and C functions callable from Lua should use.
347  */
349 {
350  return fr_lua_request;
351 }
352 
int const char * file
Definition: acutest.h:702
log_entry msg
Definition: acutest.h:794
#define RCSID(id)
Definition: build.h:444
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
char const * dl_module_search_path(void)
Definition: dl_module.c:657
#define DL_EXTENSION
Definition: dl_module.h:57
#define ROPTIONAL(_l_request, _l_global, _fmt,...)
Use different logging functions depending on whether request is NULL or not.
Definition: log.h:528
#define RWDEBUG(fmt,...)
Definition: log.h:361
#define RWARN(fmt,...)
Definition: log.h:297
#define RERROR(fmt,...)
Definition: log.h:298
#define RINFO(fmt,...)
Definition: log.h:296
talloc_free(reap)
Library function signatures for lua module.
char * strsep(char **stringp, char const *delim)
Definition: missing.c:123
Temporary structure to hold arguments for module calls.
Definition: module_ctx.h:41
static int _util_log_newindex(UNUSED lua_State *L)
Definition: util.c:141
void fr_lua_util_jit_log_warn(char const *msg)
Emit a warning log message.
Definition: util.c:176
module_ctx_t const * fr_lua_util_get_mctx(void)
Get the thread local instance.
Definition: util.c:330
int fr_lua_util_jit_log_register(lua_State *L)
Insert cdefs into the lua environment.
Definition: util.c:202
void fr_lua_util_set_mctx(module_ctx_t const *mctx)
Set the thread local instance.
Definition: util.c:321
void fr_lua_util_set_request(request_t *request)
Set the thread local request.
Definition: util.c:339
static int _util_log_debug(lua_State *L)
Lua function to output debug messages.
Definition: util.c:55
static _Thread_local module_ctx_t const * fr_lua_mctx
Definition: util.c:38
void fr_lua_util_fr_register(lua_State *L)
Definition: util.c:40
static int _util_log_info(lua_State *L)
Lua function to output informational messages.
Definition: util.c:78
static int _util_log_error(lua_State *L)
Lua function to output error messages.
Definition: util.c:125
void fr_lua_util_jit_log_error(char const *msg)
Emit a error log message.
Definition: util.c:187
void fr_lua_util_jit_log_debug(char const *msg)
Emit a debug log message.
Definition: util.c:154
static int _util_log_warn(lua_State *L)
Lua function to output warning messages.
Definition: util.c:102
static _Thread_local request_t * fr_lua_request
Definition: util.c:37
request_t * fr_lua_util_get_request(void)
Get the thread local request.
Definition: util.c:348
int fr_lua_util_log_register(lua_State *L)
Register utililiary functions in the lua environment.
Definition: util.c:280
void fr_lua_util_jit_log_info(char const *msg)
Emit an info log message.
Definition: util.c:165
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define DEBUG2(fmt,...)
Definition: radclient.h:43
#define WARN(fmt,...)
Definition: radclient.h:47
#define INFO(fmt,...)
Definition: radict.c:54
fr_assert(0)
char * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
Definition: talloc.c:333
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition: talloc.c:380