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