util.signal: Queue up multiple signals, instead of trampling on the previous debug...
[prosody.git] / util-src / lsignal.c
1 /*
2  * lsignal.h -- Signal Handler Library for Lua
3  *
4  * Version: 1.000
5  *
6  * Copyright (C) 2007  Patrick J. Donnelly (batrick@unm.edu)
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 <malloc.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   lua_pushstring(L, LUA_SIGNAL);
169   lua_gettable(L, LUA_REGISTRYINDEX);
170
171   struct signal_event *event;
172   while((event = signal_queue))
173   {
174     lua_pushnumber(L, event->Nsig);
175     lua_gettable(L, -2);
176     lua_call(L, 0, 0);
177     signal_queue = event->next_event;
178     free(event);
179   };
180
181   lua_pop(L, 1); /* pop lua_signal table */
182
183   /* restore the old hook */
184   lua_sethook(L, Hsig, Hmask, Hcount);
185 }
186
187 static void handle(int sig)
188 {
189   if(!signal_queue)
190   {
191     /* Store the existing debug hook (if any) and its parameters */
192     Hsig = lua_gethook(Lsig);
193     Hmask = lua_gethookmask(Lsig);
194     Hcount = lua_gethookcount(Lsig);
195     
196     signal_queue = malloc(sizeof(struct signal_event));
197     signal_queue->Nsig = sig;
198     signal_queue->next_event = NULL;
199
200     last_event = signal_queue;
201     
202     /* Set our new debug hook */
203     lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
204   }
205   else
206   {
207     last_event->next_event = malloc(sizeof(struct signal_event));
208     last_event->next_event->Nsig = sig;
209     last_event->next_event->next_event = NULL;
210     
211     last_event = last_event->next_event;
212   }
213 }
214
215 /*
216  * l_signal == signal(signal [, func [, chook]])
217  *
218  * signal = signal number or string
219  * func = Lua function to call
220  * chook = catch within C functions
221  *         if caught, Lua function _must_
222  *         exit, as the stack is most likely
223  *         in an unstable state.
224 */  
225
226 static int l_signal(lua_State *L)
227 {
228   int args = lua_gettop(L);
229   int t, sig; /* type, signal */
230
231   /* get type of signal */
232   luaL_checkany(L, 1);
233   t = lua_type(L, 1);
234   if (t == LUA_TNUMBER)
235     sig = (int) lua_tonumber(L, 1);
236   else if (t == LUA_TSTRING)
237   {
238     lua_pushstring(L, LUA_SIGNAL);
239     lua_gettable(L, LUA_REGISTRYINDEX);
240     lua_pushvalue(L, 1);
241     lua_gettable(L, -2);
242     if (!lua_isnumber(L, -1))
243       luaL_error(L, "invalid signal string");
244     sig = (int) lua_tonumber(L, -1);
245     lua_pop(L, 1); /* get rid of number we pushed */
246   } else
247     luaL_checknumber(L, 1); /* will always error, with good error msg */
248
249   /* set handler */
250   if (args == 1 || lua_isnil(L, 2)) /* clear handler */
251   {
252     lua_pushstring(L, LUA_SIGNAL);
253     lua_gettable(L, LUA_REGISTRYINDEX);
254     lua_pushnumber(L, sig);
255     lua_gettable(L, -2); /* return old handler */
256     lua_pushnumber(L, sig);
257     lua_pushnil(L);
258     lua_settable(L, -4);
259     lua_remove(L, -2); /* remove LUA_SIGNAL table */
260     signal(sig, SIG_DFL);
261   } else
262   {
263     luaL_checktype(L, 2, LUA_TFUNCTION);
264
265     lua_pushstring(L, LUA_SIGNAL);
266     lua_gettable(L, LUA_REGISTRYINDEX);
267
268     lua_pushnumber(L, sig);
269     lua_pushvalue(L, 2);
270     lua_settable(L, -3);
271
272     /* Set the state for the handler */
273     Lsig = L;
274
275     if (lua_toboolean(L, 3)) /* c hook? */
276     {
277       if (signal(sig, handle) == SIG_ERR)
278         lua_pushboolean(L, 0);
279       else
280         lua_pushboolean(L, 1);
281     } else /* lua_hook */
282     {
283       if (signal(sig, handle) == SIG_ERR)
284         lua_pushboolean(L, 0);
285       else
286         lua_pushboolean(L, 1);
287     }
288   }
289   return 1;
290 }
291
292 /*
293  * l_raise == raise(signal)
294  *
295  * signal = signal number or string
296 */  
297
298 static int l_raise(lua_State *L)
299 {
300   /* int args = lua_gettop(L); */
301   int t = 0; /* type */
302   lua_Number ret;
303
304   luaL_checkany(L, 1);
305
306   t = lua_type(L, 1);
307   if (t == LUA_TNUMBER)
308   {
309     ret = (lua_Number) raise((int) lua_tonumber(L, 1));
310     lua_pushnumber(L, ret);
311   } else if (t == LUA_TSTRING)
312   {
313     lua_pushstring(L, LUA_SIGNAL);
314     lua_gettable(L, LUA_REGISTRYINDEX);
315     lua_pushvalue(L, 1);
316     lua_gettable(L, -2);
317     if (!lua_isnumber(L, -1))
318       luaL_error(L, "invalid signal string");
319     ret = (lua_Number) raise((int) lua_tonumber(L, -1));
320     lua_pop(L, 1); /* get rid of number we pushed */
321     lua_pushnumber(L, ret);
322   } else
323     luaL_checknumber(L, 1); /* will always error, with good error msg */
324
325   return 1;
326 }
327
328 #if defined _POSIX_SOURCE || (defined(sun) || defined(__sun))
329
330 /* define some posix only functions */
331
332 /*
333  * l_kill == kill(pid, signal)
334  *
335  * pid = process id
336  * signal = signal number or string
337 */  
338
339 static int l_kill(lua_State *L)
340 {
341   int t; /* type */
342   lua_Number ret; /* return value */
343
344   luaL_checknumber(L, 1); /* must be int for pid */
345   luaL_checkany(L, 2); /* check for a second arg */
346
347   t = lua_type(L, 2);
348   if (t == LUA_TNUMBER)
349   {
350     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
351         (int) lua_tonumber(L, 2));
352     lua_pushnumber(L, ret);
353   } else if (t == LUA_TSTRING)
354   {
355     lua_pushstring(L, LUA_SIGNAL);
356     lua_gettable(L, LUA_REGISTRYINDEX);
357     lua_pushvalue(L, 2);
358     lua_gettable(L, -2);
359     if (!lua_isnumber(L, -1))
360       luaL_error(L, "invalid signal string");
361     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
362         (int) lua_tonumber(L, -1));
363     lua_pop(L, 1); /* get rid of number we pushed */
364     lua_pushnumber(L, ret);
365   } else
366     luaL_checknumber(L, 2); /* will always error, with good error msg */
367   return 1;
368 }
369
370 #endif
371
372 static const struct luaL_Reg lsignal_lib[] = {
373   {"signal", l_signal},
374   {"raise", l_raise},
375 #if defined _POSIX_SOURCE || (defined(sun) || defined(__sun))
376   {"kill", l_kill},
377 #endif
378   {NULL, NULL}
379 };
380
381 int luaopen_util_signal(lua_State *L)
382 {
383   int i = 0;
384
385   /* add the library */
386   luaL_register(L, "signal", lsignal_lib);
387
388   /* push lua_signals table into the registry */
389   /* put the signals inside the library table too,
390    * they are only a reference */
391   lua_pushstring(L, LUA_SIGNAL);
392   lua_createtable(L, 0, 0);
393
394   while (lua_signals[i].name != NULL)
395   {
396     /* registry table */
397     lua_pushstring(L, lua_signals[i].name);
398     lua_pushnumber(L, lua_signals[i].sig);
399     lua_settable(L, -3);
400     /* signal table */
401     lua_pushstring(L, lua_signals[i].name);
402     lua_pushnumber(L, lua_signals[i].sig);
403     lua_settable(L, -5);
404     i++;
405   }
406
407   /* add newtable to the registry */
408   lua_settable(L, LUA_REGISTRYINDEX);
409
410   return 1;
411 }