CHANGES: Update for release
[prosody.git] / util-src / signal.c
blob2268e11c8fc938bc68b6c541fe8c58cac1c800dc
1 /*
2 * signal.c -- Signal Handler Library for Lua
4 * Version: 1.000+changes
6 * Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com)
8 * This software is distributed under the same license as Lua 5.0:
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:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
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.
29 #define _GNU_SOURCE
31 #include <signal.h>
32 #include <stdlib.h>
34 #include "lua.h"
35 #include "lauxlib.h"
37 #if (LUA_VERSION_NUM == 501)
38 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
39 #endif
41 #ifndef lsig
43 #define lsig
45 struct lua_signal {
46 char *name; /* name of the signal */
47 int sig; /* the signal */
50 #endif
52 #define LUA_SIGNAL "lua_signal"
54 static const struct lua_signal lua_signals[] = {
55 /* ANSI C signals */
56 #ifdef SIGABRT
57 {"SIGABRT", SIGABRT},
58 #endif
59 #ifdef SIGFPE
60 {"SIGFPE", SIGFPE},
61 #endif
62 #ifdef SIGILL
63 {"SIGILL", SIGILL},
64 #endif
65 #ifdef SIGINT
66 {"SIGINT", SIGINT},
67 #endif
68 #ifdef SIGSEGV
69 {"SIGSEGV", SIGSEGV},
70 #endif
71 #ifdef SIGTERM
72 {"SIGTERM", SIGTERM},
73 #endif
74 /* posix signals */
75 #ifdef SIGHUP
76 {"SIGHUP", SIGHUP},
77 #endif
78 #ifdef SIGQUIT
79 {"SIGQUIT", SIGQUIT},
80 #endif
81 #ifdef SIGTRAP
82 {"SIGTRAP", SIGTRAP},
83 #endif
84 #ifdef SIGKILL
85 {"SIGKILL", SIGKILL},
86 #endif
87 #ifdef SIGUSR1
88 {"SIGUSR1", SIGUSR1},
89 #endif
90 #ifdef SIGUSR2
91 {"SIGUSR2", SIGUSR2},
92 #endif
93 #ifdef SIGPIPE
94 {"SIGPIPE", SIGPIPE},
95 #endif
96 #ifdef SIGALRM
97 {"SIGALRM", SIGALRM},
98 #endif
99 #ifdef SIGCHLD
100 {"SIGCHLD", SIGCHLD},
101 #endif
102 #ifdef SIGCONT
103 {"SIGCONT", SIGCONT},
104 #endif
105 #ifdef SIGSTOP
106 {"SIGSTOP", SIGSTOP},
107 #endif
108 #ifdef SIGTTIN
109 {"SIGTTIN", SIGTTIN},
110 #endif
111 #ifdef SIGTTOU
112 {"SIGTTOU", SIGTTOU},
113 #endif
114 /* some BSD signals */
115 #ifdef SIGIOT
116 {"SIGIOT", SIGIOT},
117 #endif
118 #ifdef SIGBUS
119 {"SIGBUS", SIGBUS},
120 #endif
121 #ifdef SIGCLD
122 {"SIGCLD", SIGCLD},
123 #endif
124 #ifdef SIGURG
125 {"SIGURG", SIGURG},
126 #endif
127 #ifdef SIGXCPU
128 {"SIGXCPU", SIGXCPU},
129 #endif
130 #ifdef SIGXFSZ
131 {"SIGXFSZ", SIGXFSZ},
132 #endif
133 #ifdef SIGVTALRM
134 {"SIGVTALRM", SIGVTALRM},
135 #endif
136 #ifdef SIGPROF
137 {"SIGPROF", SIGPROF},
138 #endif
139 #ifdef SIGWINCH
140 {"SIGWINCH", SIGWINCH},
141 #endif
142 #ifdef SIGPOLL
143 {"SIGPOLL", SIGPOLL},
144 #endif
145 #ifdef SIGIO
146 {"SIGIO", SIGIO},
147 #endif
148 /* add odd signals */
149 #ifdef SIGSTKFLT
150 {"SIGSTKFLT", SIGSTKFLT}, /* stack fault */
151 #endif
152 #ifdef SIGSYS
153 {"SIGSYS", SIGSYS},
154 #endif
155 {NULL, 0}
158 static lua_State *Lsig = NULL;
159 static lua_Hook Hsig = NULL;
160 static int Hmask = 0;
161 static int Hcount = 0;
163 static struct signal_event {
164 int Nsig;
165 struct signal_event *next_event;
166 } *signal_queue = NULL;
168 static struct signal_event *last_event = NULL;
170 static void sighook(lua_State *L, lua_Debug *ar) {
171 struct signal_event *event;
172 /* restore the old hook */
173 lua_sethook(L, Hsig, Hmask, Hcount);
175 lua_pushstring(L, LUA_SIGNAL);
176 lua_gettable(L, LUA_REGISTRYINDEX);
178 while((event = signal_queue)) {
179 lua_pushnumber(L, event->Nsig);
180 lua_gettable(L, -2);
181 lua_call(L, 0, 0);
182 signal_queue = event->next_event;
183 free(event);
186 lua_pop(L, 1); /* pop lua_signal table */
190 static void handle(int sig) {
191 if(!signal_queue) {
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);
197 signal_queue = malloc(sizeof(struct signal_event));
198 signal_queue->Nsig = sig;
199 signal_queue->next_event = NULL;
201 last_event = signal_queue;
203 /* Set our new debug hook */
204 lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
205 } else {
206 last_event->next_event = malloc(sizeof(struct signal_event));
207 last_event->next_event->Nsig = sig;
208 last_event->next_event->next_event = NULL;
210 last_event = last_event->next_event;
215 * l_signal == signal(signal [, func [, chook]])
217 * signal = signal number or string
218 * func = Lua function to call
219 * chook = catch within C functions
220 * if caught, Lua function _must_
221 * exit, as the stack is most likely
222 * in an unstable state.
225 static int l_signal(lua_State *L) {
226 int args = lua_gettop(L);
227 int t, sig; /* type, signal */
229 /* get type of signal */
230 luaL_checkany(L, 1);
231 t = lua_type(L, 1);
233 if(t == LUA_TNUMBER) {
234 sig = (int) lua_tonumber(L, 1);
235 } else if(t == LUA_TSTRING) {
236 lua_pushstring(L, LUA_SIGNAL);
237 lua_gettable(L, LUA_REGISTRYINDEX);
238 lua_pushvalue(L, 1);
239 lua_gettable(L, -2);
241 if(!lua_isnumber(L, -1)) {
242 return 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 return luaL_error(L, "unreachable: invalid number was accepted");
252 /* set handler */
253 if(args == 1 || lua_isnil(L, 2)) { /* clear handler */
254 lua_pushstring(L, LUA_SIGNAL);
255 lua_gettable(L, LUA_REGISTRYINDEX);
256 lua_pushnumber(L, sig);
257 lua_gettable(L, -2); /* return old handler */
258 lua_pushnumber(L, sig);
259 lua_pushnil(L);
260 lua_settable(L, -4);
261 lua_remove(L, -2); /* remove LUA_SIGNAL table */
262 signal(sig, SIG_DFL);
263 } else {
264 luaL_checktype(L, 2, LUA_TFUNCTION);
266 lua_pushstring(L, LUA_SIGNAL);
267 lua_gettable(L, LUA_REGISTRYINDEX);
269 lua_pushnumber(L, sig);
270 lua_pushvalue(L, 2);
271 lua_settable(L, -3);
273 /* Set the state for the handler */
274 Lsig = L;
276 if(lua_toboolean(L, 3)) { /* c hook? */
277 if(signal(sig, handle) == SIG_ERR) {
278 lua_pushboolean(L, 0);
279 } else {
280 lua_pushboolean(L, 1);
282 } else { /* lua_hook */
283 if(signal(sig, handle) == SIG_ERR) {
284 lua_pushboolean(L, 0);
285 } else {
286 lua_pushboolean(L, 1);
291 return 1;
295 * l_raise == raise(signal)
297 * signal = signal number or string
300 static int l_raise(lua_State *L) {
301 /* int args = lua_gettop(L); */
302 int t = 0; /* type */
303 lua_Number ret;
305 luaL_checkany(L, 1);
307 t = lua_type(L, 1);
309 if(t == LUA_TNUMBER) {
310 ret = (lua_Number) raise((int) lua_tonumber(L, 1));
311 lua_pushnumber(L, ret);
312 } else if(t == LUA_TSTRING) {
313 lua_pushstring(L, LUA_SIGNAL);
314 lua_gettable(L, LUA_REGISTRYINDEX);
315 lua_pushvalue(L, 1);
316 lua_gettable(L, -2);
318 if(!lua_isnumber(L, -1)) {
319 return luaL_error(L, "invalid signal string");
322 ret = (lua_Number) raise((int) lua_tonumber(L, -1));
323 lua_pop(L, 1); /* get rid of number we pushed */
324 lua_pushnumber(L, ret);
325 } else {
326 luaL_checknumber(L, 1); /* will always error, with good error msg */
329 return 1;
332 #if defined(__unix__) || defined(__APPLE__)
334 /* define some posix only functions */
337 * l_kill == kill(pid, signal)
339 * pid = process id
340 * signal = signal number or string
343 static int l_kill(lua_State *L) {
344 int t; /* type */
345 lua_Number ret; /* return value */
347 luaL_checknumber(L, 1); /* must be int for pid */
348 luaL_checkany(L, 2); /* check for a second arg */
350 t = lua_type(L, 2);
352 if(t == LUA_TNUMBER) {
353 ret = (lua_Number) kill((int) lua_tonumber(L, 1),
354 (int) lua_tonumber(L, 2));
355 lua_pushnumber(L, ret);
356 } else if(t == LUA_TSTRING) {
357 lua_pushstring(L, LUA_SIGNAL);
358 lua_gettable(L, LUA_REGISTRYINDEX);
359 lua_pushvalue(L, 2);
360 lua_gettable(L, -2);
362 if(!lua_isnumber(L, -1)) {
363 return 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 */
374 return 1;
377 #endif
379 static const struct luaL_Reg lsignal_lib[] = {
380 {"signal", l_signal},
381 {"raise", l_raise},
382 #if defined(__unix__) || defined(__APPLE__)
383 {"kill", l_kill},
384 #endif
385 {NULL, NULL}
388 int luaopen_util_signal(lua_State *L) {
389 #if (LUA_VERSION_NUM > 501)
390 luaL_checkversion(L);
391 #endif
392 int i = 0;
394 /* add the library */
395 lua_newtable(L);
396 luaL_setfuncs(L, lsignal_lib, 0);
398 /* push lua_signals table into the registry */
399 /* put the signals inside the library table too,
400 * they are only a reference */
401 lua_pushstring(L, LUA_SIGNAL);
402 lua_newtable(L);
404 while(lua_signals[i].name != NULL) {
405 /* registry table */
406 lua_pushstring(L, lua_signals[i].name);
407 lua_pushnumber(L, lua_signals[i].sig);
408 lua_settable(L, -3);
409 /* signal table */
410 lua_pushstring(L, lua_signals[i].name);
411 lua_pushnumber(L, lua_signals[i].sig);
412 lua_settable(L, -5);
413 i++;
416 /* add newtable to the registry */
417 lua_settable(L, LUA_REGISTRYINDEX);
419 return 1;