]> jfr.im git - irc/quakenet/newserv.git/blame - lua/lua.c
Lua version now excludes "Lua engine", at least for MODULEVERSION.
[irc/quakenet/newserv.git] / lua / lua.c
CommitLineData
2da56f0d
CP
1/* Lua bindings for Newserv */
2
3/* Copyright (C) Chris Porter 2005 */
4/* ALL RIGHTS RESERVED. */
5/* Don't put this into the SVN repo. */
6
7#include "../core/config.h"
8#include "../core/error.h"
9#include "../core/hooks.h"
10#include "../lib/array.h"
11#include "../lib/irc_string.h"
12#include "../core/schedule.h"
87698d77 13#include "../lib/version.h"
2da56f0d
CP
14
15#include "lua.h"
16
c3c955ee 17MODULE_VERSION(LUA_SMALLVERSION);
87698d77 18
9887536a
CP
19#ifdef LUA_DEBUGSOCKET
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <netdb.h>
26#include <unistd.h>
27#include <stdarg.h>
28
29#endif
30
2da56f0d
CP
31void lua_startup(void *arg);
32void lua_loadscripts(void);
2da56f0d 33void lua_registercommands(lua_State *l);
55cee062 34void lua_registerdbcommands(lua_State *l);
30a59b87 35void lua_initnickpusher(void);
ec91b2e4 36void lua_initchanpusher(void);
c673fb9b 37void lua_loadlibs(lua_State *l);
6269435f 38void lua_require(lua_State *l, char *module);
2da56f0d
CP
39
40void lua_startbot(void *arg);
41void lua_destroybot(void);
42void lua_startcontrol(void);
43void lua_destroycontrol(void);
44
45void lua_onunload(lua_State *l);
46void lua_onload(lua_State *l);
47
a25981bf 48void lua_setpath(lua_State *l);
2da56f0d 49
9887536a
CP
50void lua_setupdebugsocket(void);
51void lua_freedebugsocket(void);
52
0225bed3
CP
53void lua_deregisternicks(lua_list *l);
54void lua_registerlocalcommands(lua_State *ps);
f9f8ee13 55void lua_registerdebug(lua_State *ps);
065c0091
CP
56void lua_socket_closeall(lua_list *l);
57void lua_registersocketcommands(lua_State *ps);
3cf6947a 58void lua_registercryptocommands(lua_State *ps);
0225bed3 59
9887536a
CP
60#ifdef LUA_DEBUGSOCKET
61
62struct sockaddr_in debugsocketdest;
63int debugsocket = -1;
64
65#endif
66
2da56f0d
CP
67lua_list *lua_head = NULL, *lua_tail = NULL;
68
a25981bf 69sstring *cpath = NULL, *suffix = NULL;
2da56f0d
CP
70
71void *startsched = NULL;
72
a25981bf
CP
73int loaded = 0;
74
fe0f6b25
CP
75struct rusage r_usages;
76struct rusage r_usagee;
77
c673fb9b
CP
78static const luaL_Reg ourlibs[] = {
79 {"", luaopen_base},
80 {LUA_LOADLIBNAME, luaopen_package},
81 {LUA_TABLIBNAME, luaopen_table},
82 {LUA_IOLIBNAME, luaopen_io},
83 {LUA_OSLIBNAME, luaopen_os},
84 {LUA_STRLIBNAME, luaopen_string},
85 {LUA_MATHLIBNAME, luaopen_math},
9887536a 86#ifdef LUA_USEJIT
6269435f
CP
87 {LUA_JITLIBNAME, luaopen_jit},
88#endif
c673fb9b
CP
89 {NULL, NULL}
90};
d0d1e2a3
CP
91
92lua_list dummy;
c673fb9b 93
2da56f0d 94void _init() {
9887536a 95 lua_setupdebugsocket();
30a59b87 96 lua_initnickpusher();
ec91b2e4 97 lua_initchanpusher();
9887536a 98
d0d1e2a3
CP
99 dummy.name = getsstring("???", 10);
100 if(!dummy.name) {
101 Error("lua", ERR_ERROR, "Cannot set dummy name.");
102 return;
103 }
104
a25981bf
CP
105 cpath = getcopyconfigitem("lua", "scriptdir", "", 500);
106
107 if(!cpath || !cpath->content || !cpath->content[0]) {
108 Error("lua", ERR_ERROR, "Error loading path.");
109 return;
110 }
111
112 suffix = getcopyconfigitem("lua", "scriptsuffix", ".lua", 10);
113 if(!suffix) {
114 Error("lua", ERR_ERROR, "Error loading suffix.");
115 return;
116 }
117
118 loaded = 1;
119
2da56f0d
CP
120 startsched = scheduleoneshot(time(NULL) + 1, &lua_startup, NULL);
121}
122
123void lua_startup(void *arg) {
2da56f0d
CP
124 startsched = NULL;
125
2da56f0d
CP
126 lua_startcontrol();
127 lua_startbot(NULL);
128
a25981bf 129 lua_loadscripts();
2da56f0d
CP
130}
131
132#ifdef BROKEN_DLCLOSE
133void __fini() {
134#else
135void _fini() {
136#endif
2da56f0d 137
a25981bf
CP
138 if(loaded) {
139 if(startsched)
140 deleteschedule(startsched, &lua_startup, NULL);
2da56f0d 141
a25981bf
CP
142 while(lua_head)
143 lua_unloadscript(lua_head);
2da56f0d 144
a25981bf
CP
145 lua_destroybot();
146 lua_destroycontrol();
2da56f0d
CP
147 }
148
a25981bf
CP
149 freesstring(cpath);
150 freesstring(suffix);
d0d1e2a3 151 freesstring(dummy.name);
9887536a
CP
152
153 lua_freedebugsocket();
f8d5cfcf 154 nscheckfreeall(POOL_LUA);
2da56f0d
CP
155}
156
157void lua_loadscripts(void) {
158 array *ls;
159
160 ls = getconfigitems("lua", "script");
161 if(!ls) {
162 Error("lua", ERR_INFO, "No scripts loaded.");
163 } else {
164 sstring **scripts = (sstring **)(ls->content);
165 int i;
166 for(i=0;i<ls->cursi;i++)
167 lua_loadscript(scripts[i]->content);
168 }
169}
170
93917ccd
CP
171/* taken from the lua manual, modified to use nsmalloc */
172static void *lua_nsmalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
173 if(nsize == 0) {
174 if(ptr != NULL)
175 luafree(ptr);
176 return NULL;
177 }
178
179 return luarealloc(ptr, nsize);
180}
181
2da56f0d
CP
182lua_State *lua_loadscript(char *file) {
183 char fullpath[LUA_PATHLEN];
184 int top;
185 lua_State *l;
186 lua_list *n;
187
188 if(!cpath || !suffix)
189 return NULL;
190
191 delchars(file, "./\\;");
192
193 if(lua_scriptloaded(file))
194 return NULL;
195
93917ccd 196 l = lua_newstate(lua_nsmalloc, NULL);
2da56f0d
CP
197 if(!l)
198 return NULL;
199
d0e17ef9 200 n = (lua_list *)luamalloc(sizeof(lua_list));;
2da56f0d
CP
201 if(!n) {
202 Error("lua", ERR_ERROR, "Error allocing list for %s.", file);
203 return NULL;
204 }
205
206 n->name = getsstring(file, LUA_PATHLEN);
207 if(!n->name) {
208 Error("lua", ERR_ERROR, "Error allocing name item for %s.", file);
d0e17ef9 209 luafree(n);
2da56f0d
CP
210 return NULL;
211 }
d0d1e2a3 212 n->calls = 0;
2da56f0d 213
fe0f6b25
CP
214 timerclear(&n->ru_utime);
215 timerclear(&n->ru_stime);
216
c673fb9b 217 lua_loadlibs(l);
f9f8ee13 218 lua_registerdebug(l);
2da56f0d 219 lua_registercommands(l);
0225bed3 220 lua_registerlocalcommands(l);
55cee062 221 lua_registerdbcommands(l);
c7ec7d64 222 lua_registersocketcommands(l);
3cf6947a 223 lua_registercryptocommands(l);
0225bed3 224
a25981bf 225 lua_setpath(l);
2da56f0d 226
9887536a 227#ifdef LUA_USEJIT
6269435f
CP
228 lua_require(l, "lib/jit");
229#endif
230
231 lua_require(l, "lib/bootstrap");
232
2da56f0d
CP
233 snprintf(fullpath, sizeof(fullpath), "%s/%s%s", cpath->content, file, suffix->content);
234 if(luaL_loadfile(l, fullpath)) {
235 Error("lua", ERR_ERROR, "Error loading %s.", file);
236 lua_close(l);
237 freesstring(n->name);
d0e17ef9 238 luafree(n);
2da56f0d
CP
239 return NULL;
240 }
241
2da56f0d
CP
242 n->l = l;
243
244 n->next = NULL;
245 n->prev = lua_tail;
0225bed3 246 n->nicks = NULL;
065c0091 247 n->sockets = NULL;
2da56f0d
CP
248
249 if(!lua_head) {
250 lua_head = n;
251 } else {
252 lua_tail->next = n;
253 }
254
255 lua_tail = n;
256
55cee062
CP
257 top = lua_gettop(l);
258
259 if(lua_pcall(l, 0, 0, 0)) {
260 Error("lua", ERR_ERROR, "Error pcalling: %s.", file);
261 lua_close(l);
262 freesstring(n->name);
c07dd8fd
CP
263
264 if(lua_head == n)
265 lua_head = NULL;
266
267 lua_tail = n->prev;
268 if(lua_tail)
269 lua_tail->next = NULL;
270
d0e17ef9 271 luafree(n);
55cee062
CP
272 return NULL;
273 }
274
275 lua_settop(l, top);
276
277 Error("lua", ERR_INFO, "Loaded %s.", file);
2da56f0d
CP
278 lua_onload(l);
279
280 return l;
281}
282
283void lua_unloadscript(lua_list *l) {
284 lua_onunload(l->l);
0225bed3 285 lua_deregisternicks(l);
065c0091 286 lua_socket_closeall(l);
2da56f0d
CP
287 lua_close(l->l);
288 freesstring(l->name);
289
290 /* well, at least it's O(1) */
291
292 if(!l->prev) { /* head */
293 lua_head = l->next;
294 if(!lua_head) {
295 lua_tail = NULL;
296 } else {
297 lua_head->prev = NULL;
298 }
299 } else {
300 if(!l->next) { /* tail */
301 lua_tail = lua_tail->prev;
302 if(!lua_tail) {
303 lua_head = NULL;
304 } else {
305 lua_tail->next = NULL;
306 }
307 } else {
308 l->prev->next = l->next;
309 l->next->prev = l->prev;
310 }
311 }
312
d0e17ef9 313 luafree(l);
2da56f0d
CP
314}
315
a25981bf
CP
316void lua_setpath(lua_State *l) {
317 char fullpath[LUA_PATHLEN], *prev = NULL;
2da56f0d 318
a25981bf 319 int top = lua_gettop(l);
2da56f0d 320
a25981bf
CP
321 lua_getglobal(l, "package");
322 if(!lua_istable(l, 1)) {
323 Error("lua", ERR_ERROR, "Unable to set package.path (package is not a table).");
324 return;
2da56f0d
CP
325 }
326
a25981bf
CP
327 lua_pushstring(l, "path");
328 lua_gettable(l, -2);
2da56f0d 329
a25981bf
CP
330 if(lua_isstring(l, -1))
331 prev = (char *)lua_tostring(l, -1);
332
333 if(prev) {
334 snprintf(fullpath, sizeof(fullpath), "%s;%s/?%s", prev, cpath->content, suffix->content);
2da56f0d 335 } else {
c673fb9b 336 snprintf(fullpath, sizeof(fullpath), "%s/?%s", cpath->content, suffix->content);
2da56f0d 337 }
2da56f0d 338
2f51c193
CP
339 /* pop broke! */
340
341 lua_getglobal(l, "package");
342 if(!lua_istable(l, 1)) {
343 Error("lua", ERR_ERROR, "Unable to set package.path (package is not a table).");
344 return;
345 }
346
347 lua_pushstring(l, "path");
2da56f0d 348
a25981bf
CP
349 lua_pushstring(l, fullpath);
350 lua_settable(l, -3);
351
352 lua_settop(l, top);
2da56f0d
CP
353}
354
355lua_list *lua_scriptloaded(char *name) {
356 lua_list *l;
357
358 for(l=lua_head;l;l=l->next)
359 if(!strcmp(l->name->content, name))
360 return l;
361
362 return NULL;
363}
364
c673fb9b
CP
365void lua_loadlibs(lua_State *l) {
366 const luaL_Reg *lib = ourlibs;
367
368 for (;lib->func;lib++) {
369 lua_pushcfunction(l, lib->func);
370 lua_pushstring(l, lib->name);
371 lua_call(l, 1, 0);
372 }
373}
6269435f
CP
374
375void lua_require(lua_State *l, char *module) {
376 int top = lua_gettop(l);
377
378 lua_getglobal(l, "require");
379 lua_pushstring(l, module);
380
381 if(lua_pcall(l, 1, 1, 0))
382 Error("lua", ERR_ERROR, "Error requiring %s: %s", module, lua_tostring(l, -1));
383
384 lua_settop(l, top);
385}
386
9887536a
CP
387void lua_setupdebugsocket(void) {
388#ifdef LUA_DEBUGSOCKET
389
390 debugsocket = socket(AF_INET, SOCK_DGRAM, 0);
391 if(debugsocket < 0) {
392 debugsocket = -1;
393 Error("lua", ERR_ERROR, "Cannot create debug socket.");
394
395 return;
396 }
397
398 memset(&debugsocketdest, 0, sizeof(debugsocketdest));
399
400 debugsocketdest.sin_family = AF_INET;
401 debugsocketdest.sin_port = htons(LUA_DEBUGSOCKET_PORT);
402 debugsocketdest.sin_addr.s_addr = inet_addr(LUA_DEBUGSOCKET_ADDRESS);
403
404#endif
405}
406
407void lua_freedebugsocket(void) {
408#ifdef LUA_DEBUGSOCKET
409
410 if(debugsocket == -1)
411 return;
412
413 close(debugsocket);
414
415
416 debugsocket = -1;
417
418#endif
419}
420
421#ifdef LUA_DEBUGSOCKET
422void lua_debugoutput(char *format, ...) {
423 char buf[1024];
424 va_list va;
425 int size;
426
427 if(debugsocket == -1)
428 return;
429
430 va_start(va, format);
431 size = vsnprintf(buf, sizeof(buf), format, va);
432 va_end(va);
433
434 if(size >= sizeof(buf))
435 size = sizeof(buf) - 1;
436
437 if(size > 0)
438 sendto(debugsocket, buf, size, 0, (struct sockaddr *)&debugsocketdest, sizeof(debugsocketdest));
439}
440#endif
441
d0d1e2a3 442lua_list *lua_listfromstate(lua_State *l) {
9887536a
CP
443 lua_list *i = lua_head;
444 for(;i;i=i->next)
445 if(i->l == l)
d0d1e2a3 446 return i;
9887536a 447
d0d1e2a3 448 return &dummy;
9887536a 449}
6269435f 450
55cee062
CP
451int lua_listexists(lua_list *l) {
452 lua_list *i;
453
454 for(i=lua_head;i;i=i->next)
455 if(i == l)
456 return 1;
457
458 return 0;
459}
460
0225bed3
CP
461int lua_lineok(const char *data) {
462 if(strchr(data, '\r') || strchr(data, '\n'))
463 return 0;
464 return 1;
465}
466
ea15be33
CP
467INLINE int lua_debugpcall(lua_State *l, char *message, int a, int b, int c) {
468 lua_list *l2 = lua_listfromstate(l);
469 int ret;
470
471#ifdef LUA_DEBUGSOCKET
472 DEBUGOUT("%s: %s\n", l2->name->content, message);
473#endif
474
475#ifdef LUA_PROFILE
476 ACCOUNTING_START(l2);
477#endif
478
479 ret = lua_pcall(l, a, b, c);
480
481#ifdef LUA_PROFILE
482 ACCOUNTING_STOP(l2);
483#endif
484
485 return ret;
486}
0225bed3 487