net.server_event: Check the buffer *length*, not the buffer itself (Fixes 100% cpu...
[prosody.git] / util-src / signal.c
1 /*
2  * signal.c -- Signal Handler Library for Lua
3  *
4  * Version: 1.000+changes
5  *
6  * Copyright (C) 2007  Patrick J. Donnelly (batrick@batbytes.com)
7  *
8  * This software is distributed under the same license as Lua 5.0:
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE. 
27 */
28
29 #include <signal.h>
30 #include <stdlib.h>
31
32 #include "lua.h"
33 #include "lauxlib.h"
34
35 #ifndef lsig
36
37 #define lsig
38
39 struct lua_signal
40 {
41   char *name; /* name of the signal */
42   int sig; /* the signal */
43 };
44
45 #endif
46
47 #define LUA_SIGNAL "lua_signal"
48
49 static const struct lua_signal lua_signals[] = {
50   /* ANSI C signals */
51 #ifdef SIGABRT
52   {"SIGABRT", SIGABRT},
53 #endif
54 #ifdef SIGFPE
55   {"SIGFPE", SIGFPE},
56 #endif
57 #ifdef SIGILL
58   {"SIGILL", SIGILL},
59 #endif
60 #ifdef SIGINT
61   {"SIGINT", SIGINT},
62 #endif
63 #ifdef SIGSEGV
64   {"SIGSEGV", SIGSEGV},
65 #endif
66 #ifdef SIGTERM
67   {"SIGTERM", SIGTERM},
68 #endif
69   /* posix signals */
70 #ifdef SIGHUP
71   {"SIGHUP", SIGHUP},
72 #endif
73 #ifdef SIGQUIT
74   {"SIGQUIT", SIGQUIT},
75 #endif
76 #ifdef SIGTRAP
77   {"SIGTRAP", SIGTRAP},
78 #endif
79 #ifdef SIGKILL
80   {"SIGKILL", SIGKILL},
81 #endif
82 #ifdef SIGUSR1
83   {"SIGUSR1", SIGUSR1},
84 #endif
85 #ifdef SIGUSR2
86   {"SIGUSR2", SIGUSR2},
87 #endif
88 #ifdef SIGPIPE
89   {"SIGPIPE", SIGPIPE},
90 #endif
91 #ifdef SIGALRM
92   {"SIGALRM", SIGALRM},
93 #endif
94 #ifdef SIGCHLD
95   {"SIGCHLD", SIGCHLD},
96 #endif
97 #ifdef SIGCONT
98   {"SIGCONT", SIGCONT},
99 #endif
100 #ifdef SIGSTOP
101   {"SIGSTOP", SIGSTOP},
102 #endif
103 #ifdef SIGTTIN
104   {"SIGTTIN", SIGTTIN},
105 #endif
106 #ifdef SIGTTOU
107   {"SIGTTOU", SIGTTOU},
108 #endif
109   /* some BSD signals */
110 #ifdef SIGIOT
111   {"SIGIOT", SIGIOT},
112 #endif
113 #ifdef SIGBUS
114   {"SIGBUS", SIGBUS},
115 #endif
116 #ifdef SIGCLD
117   {"SIGCLD", SIGCLD},
118 #endif
119 #ifdef SIGURG
120   {"SIGURG", SIGURG},
121 #endif
122 #ifdef SIGXCPU
123   {"SIGXCPU", SIGXCPU},
124 #endif
125 #ifdef SIGXFSZ
126   {"SIGXFSZ", SIGXFSZ},
127 #endif
128 #ifdef SIGVTALRM
129   {"SIGVTALRM", SIGVTALRM},
130 #endif
131 #ifdef SIGPROF
132   {"SIGPROF", SIGPROF},
133 #endif
134 #ifdef SIGWINCH
135   {"SIGWINCH", SIGWINCH},
136 #endif
137 #ifdef SIGPOLL
138   {"SIGPOLL", SIGPOLL},
139 #endif
140 #ifdef SIGIO
141   {"SIGIO", SIGIO},
142 #endif
143   /* add odd signals */
144 #ifdef SIGSTKFLT
145   {"SIGSTKFLT", SIGSTKFLT}, /* stack fault */
146 #endif
147 #ifdef SIGSYS
148   {"SIGSYS", SIGSYS},
149 #endif
150   {NULL, 0}
151 };
152
153 static lua_State *Lsig = NULL;
154 static lua_Hook Hsig = NULL;
155 static int Hmask = 0;
156 static int Hcount = 0;
157
158 static struct signal_event
159 {
160         int Nsig;
161         struct signal_event *next_event;
162 } *signal_queue = NULL;
163
164 static struct signal_event *last_event = NULL;
165
166 static void sighook(lua_State *L, lua_Debug *ar)
167 {
168   struct signal_event *event;
169   /* restore the old hook */
170   lua_sethook(L, Hsig, Hmask, Hcount);
171
172   lua_pushstring(L, LUA_SIGNAL);
173   lua_gettable(L, LUA_REGISTRYINDEX);
174
175   while((event = signal_queue))
176   {
177     lua_pushnumber(L, event->Nsig);
178     lua_gettable(L, -2);
179     lua_call(L, 0, 0);
180     signal_queue = event->next_event;
181     free(event);
182   };
183
184   lua_pop(L, 1); /* pop lua_signal table */
185
186 }
187
188 static void handle(int sig)
189 {
190   if(!signal_queue)
191   {
192     /* Store the existing debug hook (if any) and its parameters */
193     Hsig = lua_gethook(Lsig);
194     Hmask = lua_gethookmask(Lsig);
195     Hcount = lua_gethookcount(Lsig);
196     
197     signal_queue = malloc(sizeof(struct signal_event));
198     signal_queue->Nsig = sig;
199     signal_queue->next_event = NULL;
200
201     last_event = signal_queue;
202     
203     /* Set our new debug hook */
204     lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
205   }
206   else
207   {
208     last_event->next_event = malloc(sizeof(struct signal_event));
209     last_event->next_event->Nsig = sig;
210     last_event->next_event->next_event = NULL;
211     
212     last_event = last_event->next_event;
213   }
214 }
215
216 /*
217  * l_signal == signal(signal [, func [, chook]])
218  *
219  * signal = signal number or string
220  * func = Lua function to call
221  * chook = catch within C functions
222  *         if caught, Lua function _must_
223  *         exit, as the stack is most likely
224  *         in an unstable state.
225 */  
226
227 static int l_signal(lua_State *L)
228 {
229   int args = lua_gettop(L);
230   int t, sig; /* type, signal */
231
232   /* get type of signal */
233   luaL_checkany(L, 1);
234   t = lua_type(L, 1);
235   if (t == LUA_TNUMBER)
236     sig = (int) lua_tonumber(L, 1);
237   else if (t == LUA_TSTRING)
238   {
239     lua_pushstring(L, LUA_SIGNAL);
240     lua_gettable(L, LUA_REGISTRYINDEX);
241     lua_pushvalue(L, 1);
242     lua_gettable(L, -2);
243     if (!lua_isnumber(L, -1))
244       luaL_error(L, "invalid signal string");
245     sig = (int) lua_tonumber(L, -1);
246     lua_pop(L, 1); /* get rid of number we pushed */
247   } else
248     luaL_checknumber(L, 1); /* will always error, with good error msg */
249
250   /* set handler */
251   if (args == 1 || lua_isnil(L, 2)) /* clear handler */
252   {
253     lua_pushstring(L, LUA_SIGNAL);
254     lua_gettable(L, LUA_REGISTRYINDEX);
255     lua_pushnumber(L, sig);
256     lua_gettable(L, -2); /* return old handler */
257     lua_pushnumber(L, sig);
258     lua_pushnil(L);
259     lua_settable(L, -4);
260     lua_remove(L, -2); /* remove LUA_SIGNAL table */
261     signal(sig, SIG_DFL);
262   } else
263   {
264     luaL_checktype(L, 2, LUA_TFUNCTION);
265
266     lua_pushstring(L, LUA_SIGNAL);
267     lua_gettable(L, LUA_REGISTRYINDEX);
268
269     lua_pushnumber(L, sig);
270     lua_pushvalue(L, 2);
271     lua_settable(L, -3);
272
273     /* Set the state for the handler */
274     Lsig = L;
275
276     if (lua_toboolean(L, 3)) /* c hook? */
277     {
278       if (signal(sig, handle) == SIG_ERR)
279         lua_pushboolean(L, 0);
280       else
281         lua_pushboolean(L, 1);
282     } else /* lua_hook */
283     {
284       if (signal(sig, handle) == SIG_ERR)
285         lua_pushboolean(L, 0);
286       else
287         lua_pushboolean(L, 1);
288     }
289   }
290   return 1;
291 }
292
293 /*
294  * l_raise == raise(signal)
295  *
296  * signal = signal number or string
297 */  
298
299 static int l_raise(lua_State *L)
300 {
301   /* int args = lua_gettop(L); */
302   int t = 0; /* type */
303   lua_Number ret;
304
305   luaL_checkany(L, 1);
306
307   t = lua_type(L, 1);
308   if (t == LUA_TNUMBER)
309   {
310     ret = (lua_Number) raise((int) lua_tonumber(L, 1));
311     lua_pushnumber(L, ret);
312   } else if (t == LUA_TSTRING)
313   {
314     lua_pushstring(L, LUA_SIGNAL);
315     lua_gettable(L, LUA_REGISTRYINDEX);
316     lua_pushvalue(L, 1);
317     lua_gettable(L, -2);
318     if (!lua_isnumber(L, -1))
319       luaL_error(L, "invalid signal string");
320     ret = (lua_Number) raise((int) lua_tonumber(L, -1));
321     lua_pop(L, 1); /* get rid of number we pushed */
322     lua_pushnumber(L, ret);
323   } else
324     luaL_checknumber(L, 1); /* will always error, with good error msg */
325
326   return 1;
327 }
328
329 #if defined(__unix__) || defined(__APPLE__)
330
331 /* define some posix only functions */
332
333 /*
334  * l_kill == kill(pid, signal)
335  *
336  * pid = process id
337  * signal = signal number or string
338 */  
339
340 static int l_kill(lua_State *L)
341 {
342   int t; /* type */
343   lua_Number ret; /* return value */
344
345   luaL_checknumber(L, 1); /* must be int for pid */
346   luaL_checkany(L, 2); /* check for a second arg */
347
348   t = lua_type(L, 2);
349   if (t == LUA_TNUMBER)
350   {
351     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
352         (int) lua_tonumber(L, 2));
353     lua_pushnumber(L, ret);
354   } else if (t == LUA_TSTRING)
355   {
356     lua_pushstring(L, LUA_SIGNAL);
357     lua_gettable(L, LUA_REGISTRYINDEX);
358     lua_pushvalue(L, 2);
359     lua_gettable(L, -2);
360     if (!lua_isnumber(L, -1))
361       luaL_error(L, "invalid signal string");
362     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
363         (int) lua_tonumber(L, -1));
364     lua_pop(L, 1); /* get rid of number we pushed */
365     lua_pushnumber(L, ret);
366   } else
367     luaL_checknumber(L, 2); /* will always error, with good error msg */
368   return 1;
369 }
370
371 #endif
372
373 static const struct luaL_Reg lsignal_lib[] = {
374   {"signal", l_signal},
375   {"raise", l_raise},
376 #if defined(__unix__) || defined(__APPLE__)
377   {"kill", l_kill},
378 #endif
379   {NULL, NULL}
380 };
381
382 int luaopen_util_signal(lua_State *L)
383 {
384   int i = 0;
385
386   /* add the library */
387   luaL_register(L, "signal", lsignal_lib);
388
389   /* push lua_signals table into the registry */
390   /* put the signals inside the library table too,
391    * they are only a reference */
392   lua_pushstring(L, LUA_SIGNAL);
393   lua_createtable(L, 0, 0);
394
395   while (lua_signals[i].name != NULL)
396   {
397     /* registry table */
398     lua_pushstring(L, lua_signals[i].name);
399     lua_pushnumber(L, lua_signals[i].sig);
400     lua_settable(L, -3);
401     /* signal table */
402     lua_pushstring(L, lua_signals[i].name);
403     lua_pushnumber(L, lua_signals[i].sig);
404     lua_settable(L, -5);
405     i++;
406   }
407
408   /* add newtable to the registry */
409   lua_settable(L, LUA_REGISTRYINDEX);
410
411   return 1;
412 }