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