Merge 0.9->0.10
[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 #if (LUA_VERSION_NUM == 502)
36 #define luaL_register(L, N, R) luaL_setfuncs(L, R, 0)
37 #endif
38
39 #ifndef lsig
40
41 #define lsig
42
43 struct lua_signal
44 {
45   char *name; /* name of the signal */
46   int sig; /* the signal */
47 };
48
49 #endif
50
51 #define LUA_SIGNAL "lua_signal"
52
53 static const struct lua_signal lua_signals[] = {
54   /* ANSI C signals */
55 #ifdef SIGABRT
56   {"SIGABRT", SIGABRT},
57 #endif
58 #ifdef SIGFPE
59   {"SIGFPE", SIGFPE},
60 #endif
61 #ifdef SIGILL
62   {"SIGILL", SIGILL},
63 #endif
64 #ifdef SIGINT
65   {"SIGINT", SIGINT},
66 #endif
67 #ifdef SIGSEGV
68   {"SIGSEGV", SIGSEGV},
69 #endif
70 #ifdef SIGTERM
71   {"SIGTERM", SIGTERM},
72 #endif
73   /* posix signals */
74 #ifdef SIGHUP
75   {"SIGHUP", SIGHUP},
76 #endif
77 #ifdef SIGQUIT
78   {"SIGQUIT", SIGQUIT},
79 #endif
80 #ifdef SIGTRAP
81   {"SIGTRAP", SIGTRAP},
82 #endif
83 #ifdef SIGKILL
84   {"SIGKILL", SIGKILL},
85 #endif
86 #ifdef SIGUSR1
87   {"SIGUSR1", SIGUSR1},
88 #endif
89 #ifdef SIGUSR2
90   {"SIGUSR2", SIGUSR2},
91 #endif
92 #ifdef SIGPIPE
93   {"SIGPIPE", SIGPIPE},
94 #endif
95 #ifdef SIGALRM
96   {"SIGALRM", SIGALRM},
97 #endif
98 #ifdef SIGCHLD
99   {"SIGCHLD", SIGCHLD},
100 #endif
101 #ifdef SIGCONT
102   {"SIGCONT", SIGCONT},
103 #endif
104 #ifdef SIGSTOP
105   {"SIGSTOP", SIGSTOP},
106 #endif
107 #ifdef SIGTTIN
108   {"SIGTTIN", SIGTTIN},
109 #endif
110 #ifdef SIGTTOU
111   {"SIGTTOU", SIGTTOU},
112 #endif
113   /* some BSD signals */
114 #ifdef SIGIOT
115   {"SIGIOT", SIGIOT},
116 #endif
117 #ifdef SIGBUS
118   {"SIGBUS", SIGBUS},
119 #endif
120 #ifdef SIGCLD
121   {"SIGCLD", SIGCLD},
122 #endif
123 #ifdef SIGURG
124   {"SIGURG", SIGURG},
125 #endif
126 #ifdef SIGXCPU
127   {"SIGXCPU", SIGXCPU},
128 #endif
129 #ifdef SIGXFSZ
130   {"SIGXFSZ", SIGXFSZ},
131 #endif
132 #ifdef SIGVTALRM
133   {"SIGVTALRM", SIGVTALRM},
134 #endif
135 #ifdef SIGPROF
136   {"SIGPROF", SIGPROF},
137 #endif
138 #ifdef SIGWINCH
139   {"SIGWINCH", SIGWINCH},
140 #endif
141 #ifdef SIGPOLL
142   {"SIGPOLL", SIGPOLL},
143 #endif
144 #ifdef SIGIO
145   {"SIGIO", SIGIO},
146 #endif
147   /* add odd signals */
148 #ifdef SIGSTKFLT
149   {"SIGSTKFLT", SIGSTKFLT}, /* stack fault */
150 #endif
151 #ifdef SIGSYS
152   {"SIGSYS", SIGSYS},
153 #endif
154   {NULL, 0}
155 };
156
157 static lua_State *Lsig = NULL;
158 static lua_Hook Hsig = NULL;
159 static int Hmask = 0;
160 static int Hcount = 0;
161
162 static struct signal_event
163 {
164         int Nsig;
165         struct signal_event *next_event;
166 } *signal_queue = NULL;
167
168 static struct signal_event *last_event = NULL;
169
170 static void sighook(lua_State *L, lua_Debug *ar)
171 {
172   struct signal_event *event;
173   /* restore the old hook */
174   lua_sethook(L, Hsig, Hmask, Hcount);
175
176   lua_pushstring(L, LUA_SIGNAL);
177   lua_gettable(L, LUA_REGISTRYINDEX);
178
179   while((event = signal_queue))
180   {
181     lua_pushnumber(L, event->Nsig);
182     lua_gettable(L, -2);
183     lua_call(L, 0, 0);
184     signal_queue = event->next_event;
185     free(event);
186   };
187
188   lua_pop(L, 1); /* pop lua_signal table */
189
190 }
191
192 static void handle(int sig)
193 {
194   if(!signal_queue)
195   {
196     /* Store the existing debug hook (if any) and its parameters */
197     Hsig = lua_gethook(Lsig);
198     Hmask = lua_gethookmask(Lsig);
199     Hcount = lua_gethookcount(Lsig);
200     
201     signal_queue = malloc(sizeof(struct signal_event));
202     signal_queue->Nsig = sig;
203     signal_queue->next_event = NULL;
204
205     last_event = signal_queue;
206     
207     /* Set our new debug hook */
208     lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
209   }
210   else
211   {
212     last_event->next_event = malloc(sizeof(struct signal_event));
213     last_event->next_event->Nsig = sig;
214     last_event->next_event->next_event = NULL;
215     
216     last_event = last_event->next_event;
217   }
218 }
219
220 /*
221  * l_signal == signal(signal [, func [, chook]])
222  *
223  * signal = signal number or string
224  * func = Lua function to call
225  * chook = catch within C functions
226  *         if caught, Lua function _must_
227  *         exit, as the stack is most likely
228  *         in an unstable state.
229 */  
230
231 static int l_signal(lua_State *L)
232 {
233   int args = lua_gettop(L);
234   int t, sig; /* type, signal */
235
236   /* get type of signal */
237   luaL_checkany(L, 1);
238   t = lua_type(L, 1);
239   if (t == LUA_TNUMBER)
240     sig = (int) lua_tonumber(L, 1);
241   else if (t == LUA_TSTRING)
242   {
243     lua_pushstring(L, LUA_SIGNAL);
244     lua_gettable(L, LUA_REGISTRYINDEX);
245     lua_pushvalue(L, 1);
246     lua_gettable(L, -2);
247     if (!lua_isnumber(L, -1))
248       luaL_error(L, "invalid signal string");
249     sig = (int) lua_tonumber(L, -1);
250     lua_pop(L, 1); /* get rid of number we pushed */
251   } else
252     luaL_checknumber(L, 1); /* will always error, with good error msg */
253
254   /* set handler */
255   if (args == 1 || lua_isnil(L, 2)) /* clear handler */
256   {
257     lua_pushstring(L, LUA_SIGNAL);
258     lua_gettable(L, LUA_REGISTRYINDEX);
259     lua_pushnumber(L, sig);
260     lua_gettable(L, -2); /* return old handler */
261     lua_pushnumber(L, sig);
262     lua_pushnil(L);
263     lua_settable(L, -4);
264     lua_remove(L, -2); /* remove LUA_SIGNAL table */
265     signal(sig, SIG_DFL);
266   } else
267   {
268     luaL_checktype(L, 2, LUA_TFUNCTION);
269
270     lua_pushstring(L, LUA_SIGNAL);
271     lua_gettable(L, LUA_REGISTRYINDEX);
272
273     lua_pushnumber(L, sig);
274     lua_pushvalue(L, 2);
275     lua_settable(L, -3);
276
277     /* Set the state for the handler */
278     Lsig = L;
279
280     if (lua_toboolean(L, 3)) /* c hook? */
281     {
282       if (signal(sig, handle) == SIG_ERR)
283         lua_pushboolean(L, 0);
284       else
285         lua_pushboolean(L, 1);
286     } else /* lua_hook */
287     {
288       if (signal(sig, handle) == SIG_ERR)
289         lua_pushboolean(L, 0);
290       else
291         lua_pushboolean(L, 1);
292     }
293   }
294   return 1;
295 }
296
297 /*
298  * l_raise == raise(signal)
299  *
300  * signal = signal number or string
301 */  
302
303 static int l_raise(lua_State *L)
304 {
305   /* int args = lua_gettop(L); */
306   int t = 0; /* type */
307   lua_Number ret;
308
309   luaL_checkany(L, 1);
310
311   t = lua_type(L, 1);
312   if (t == LUA_TNUMBER)
313   {
314     ret = (lua_Number) raise((int) lua_tonumber(L, 1));
315     lua_pushnumber(L, ret);
316   } else if (t == LUA_TSTRING)
317   {
318     lua_pushstring(L, LUA_SIGNAL);
319     lua_gettable(L, LUA_REGISTRYINDEX);
320     lua_pushvalue(L, 1);
321     lua_gettable(L, -2);
322     if (!lua_isnumber(L, -1))
323       luaL_error(L, "invalid signal string");
324     ret = (lua_Number) raise((int) lua_tonumber(L, -1));
325     lua_pop(L, 1); /* get rid of number we pushed */
326     lua_pushnumber(L, ret);
327   } else
328     luaL_checknumber(L, 1); /* will always error, with good error msg */
329
330   return 1;
331 }
332
333 #if defined(__unix__) || defined(__APPLE__)
334
335 /* define some posix only functions */
336
337 /*
338  * l_kill == kill(pid, signal)
339  *
340  * pid = process id
341  * signal = signal number or string
342 */  
343
344 static int l_kill(lua_State *L)
345 {
346   int t; /* type */
347   lua_Number ret; /* return value */
348
349   luaL_checknumber(L, 1); /* must be int for pid */
350   luaL_checkany(L, 2); /* check for a second arg */
351
352   t = lua_type(L, 2);
353   if (t == LUA_TNUMBER)
354   {
355     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
356         (int) lua_tonumber(L, 2));
357     lua_pushnumber(L, ret);
358   } else if (t == LUA_TSTRING)
359   {
360     lua_pushstring(L, LUA_SIGNAL);
361     lua_gettable(L, LUA_REGISTRYINDEX);
362     lua_pushvalue(L, 2);
363     lua_gettable(L, -2);
364     if (!lua_isnumber(L, -1))
365       luaL_error(L, "invalid signal string");
366     ret = (lua_Number) kill((int) lua_tonumber(L, 1),
367         (int) lua_tonumber(L, -1));
368     lua_pop(L, 1); /* get rid of number we pushed */
369     lua_pushnumber(L, ret);
370   } else
371     luaL_checknumber(L, 2); /* will always error, with good error msg */
372   return 1;
373 }
374
375 #endif
376
377 static const struct luaL_Reg lsignal_lib[] = {
378   {"signal", l_signal},
379   {"raise", l_raise},
380 #if defined(__unix__) || defined(__APPLE__)
381   {"kill", l_kill},
382 #endif
383   {NULL, NULL}
384 };
385
386 int luaopen_util_signal(lua_State *L)
387 {
388   int i = 0;
389
390   /* add the library */
391   lua_newtable(L);
392   luaL_register(L, NULL, lsignal_lib);
393
394   /* push lua_signals table into the registry */
395   /* put the signals inside the library table too,
396    * they are only a reference */
397   lua_pushstring(L, LUA_SIGNAL);
398   lua_newtable(L);
399
400   while (lua_signals[i].name != NULL)
401   {
402     /* registry table */
403     lua_pushstring(L, lua_signals[i].name);
404     lua_pushnumber(L, lua_signals[i].sig);
405     lua_settable(L, -3);
406     /* signal table */
407     lua_pushstring(L, lua_signals[i].name);
408     lua_pushnumber(L, lua_signals[i].sig);
409     lua_settable(L, -5);
410     i++;
411   }
412
413   /* add newtable to the registry */
414   lua_settable(L, LUA_REGISTRYINDEX);
415
416   return 1;
417 }