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