mod_admin_telnet: Identify native bidi sessions
[prosody.git] / util-src / signal.c
blobc696a3a2d6c157d5d06cc621f6d97d6b8302b773
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 #ifndef _GNU_SOURCE
30 #define _GNU_SOURCE
31 #endif
33 #include <signal.h>
34 #include <stdlib.h>
36 #include "lua.h"
37 #include "lauxlib.h"
39 #if (LUA_VERSION_NUM == 501)
40 #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R)
41 #endif
43 #ifndef lsig
45 #define lsig
47 struct lua_signal {
48 char *name; /* name of the signal */
49 int sig; /* the signal */
52 #endif
54 #define MAX_PENDING_SIGNALS 32
56 #define LUA_SIGNAL "lua_signal"
58 static const struct lua_signal lua_signals[] = {
59 /* ANSI C signals */
60 #ifdef SIGABRT
61 {"SIGABRT", SIGABRT},
62 #endif
63 #ifdef SIGFPE
64 {"SIGFPE", SIGFPE},
65 #endif
66 #ifdef SIGILL
67 {"SIGILL", SIGILL},
68 #endif
69 #ifdef SIGINT
70 {"SIGINT", SIGINT},
71 #endif
72 #ifdef SIGSEGV
73 {"SIGSEGV", SIGSEGV},
74 #endif
75 #ifdef SIGTERM
76 {"SIGTERM", SIGTERM},
77 #endif
78 /* posix signals */
79 #ifdef SIGHUP
80 {"SIGHUP", SIGHUP},
81 #endif
82 #ifdef SIGQUIT
83 {"SIGQUIT", SIGQUIT},
84 #endif
85 #ifdef SIGTRAP
86 {"SIGTRAP", SIGTRAP},
87 #endif
88 #ifdef SIGKILL
89 {"SIGKILL", SIGKILL},
90 #endif
91 #ifdef SIGUSR1
92 {"SIGUSR1", SIGUSR1},
93 #endif
94 #ifdef SIGUSR2
95 {"SIGUSR2", SIGUSR2},
96 #endif
97 #ifdef SIGPIPE
98 {"SIGPIPE", SIGPIPE},
99 #endif
100 #ifdef SIGALRM
101 {"SIGALRM", SIGALRM},
102 #endif
103 #ifdef SIGCHLD
104 {"SIGCHLD", SIGCHLD},
105 #endif
106 #ifdef SIGCONT
107 {"SIGCONT", SIGCONT},
108 #endif
109 #ifdef SIGSTOP
110 {"SIGSTOP", SIGSTOP},
111 #endif
112 #ifdef SIGTTIN
113 {"SIGTTIN", SIGTTIN},
114 #endif
115 #ifdef SIGTTOU
116 {"SIGTTOU", SIGTTOU},
117 #endif
118 /* some BSD signals */
119 #ifdef SIGIOT
120 {"SIGIOT", SIGIOT},
121 #endif
122 #ifdef SIGBUS
123 {"SIGBUS", SIGBUS},
124 #endif
125 #ifdef SIGCLD
126 {"SIGCLD", SIGCLD},
127 #endif
128 #ifdef SIGURG
129 {"SIGURG", SIGURG},
130 #endif
131 #ifdef SIGXCPU
132 {"SIGXCPU", SIGXCPU},
133 #endif
134 #ifdef SIGXFSZ
135 {"SIGXFSZ", SIGXFSZ},
136 #endif
137 #ifdef SIGVTALRM
138 {"SIGVTALRM", SIGVTALRM},
139 #endif
140 #ifdef SIGPROF
141 {"SIGPROF", SIGPROF},
142 #endif
143 #ifdef SIGWINCH
144 {"SIGWINCH", SIGWINCH},
145 #endif
146 #ifdef SIGPOLL
147 {"SIGPOLL", SIGPOLL},
148 #endif
149 #ifdef SIGIO
150 {"SIGIO", SIGIO},
151 #endif
152 /* add odd signals */
153 #ifdef SIGSTKFLT
154 {"SIGSTKFLT", SIGSTKFLT}, /* stack fault */
155 #endif
156 #ifdef SIGSYS
157 {"SIGSYS", SIGSYS},
158 #endif
159 {NULL, 0}
162 static lua_State *Lsig = NULL;
163 static lua_Hook Hsig = NULL;
164 static int Hmask = 0;
165 static int Hcount = 0;
167 int signals[MAX_PENDING_SIGNALS];
168 int nsig = 0;
170 static void sighook(lua_State *L, lua_Debug *ar) {
171 (void)ar;
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 for(int i = 0; i < nsig; i++) {
179 lua_pushnumber(L, signals[i]);
180 lua_gettable(L, -2);
181 lua_call(L, 0, 0);
184 nsig = 0;
186 lua_pop(L, 1); /* pop lua_signal table */
190 static void handle(int sig) {
191 if(nsig == 0) {
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 /* Set our new debug hook */
198 lua_sethook(Lsig, sighook, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
201 if(nsig < MAX_PENDING_SIGNALS) {
202 signals[nsig++] = sig;
207 * l_signal == signal(signal [, func [, chook]])
209 * signal = signal number or string
210 * func = Lua function to call
211 * chook = catch within C functions
212 * if caught, Lua function _must_
213 * exit, as the stack is most likely
214 * in an unstable state.
217 static int l_signal(lua_State *L) {
218 int args = lua_gettop(L);
219 int t, sig; /* type, signal */
221 /* get type of signal */
222 luaL_checkany(L, 1);
223 t = lua_type(L, 1);
225 if(t == LUA_TNUMBER) {
226 sig = (int) lua_tonumber(L, 1);
227 } else if(t == LUA_TSTRING) {
228 lua_pushstring(L, LUA_SIGNAL);
229 lua_gettable(L, LUA_REGISTRYINDEX);
230 lua_pushvalue(L, 1);
231 lua_gettable(L, -2);
233 if(!lua_isnumber(L, -1)) {
234 return luaL_error(L, "invalid signal string");
237 sig = (int) lua_tonumber(L, -1);
238 lua_pop(L, 1); /* get rid of number we pushed */
239 } else {
240 luaL_checknumber(L, 1); /* will always error, with good error msg */
241 return luaL_error(L, "unreachable: invalid number was accepted");
244 /* set handler */
245 if(args == 1 || lua_isnil(L, 2)) { /* clear handler */
246 lua_pushstring(L, LUA_SIGNAL);
247 lua_gettable(L, LUA_REGISTRYINDEX);
248 lua_pushnumber(L, sig);
249 lua_gettable(L, -2); /* return old handler */
250 lua_pushnumber(L, sig);
251 lua_pushnil(L);
252 lua_settable(L, -4);
253 lua_remove(L, -2); /* remove LUA_SIGNAL table */
254 signal(sig, SIG_DFL);
255 } else {
256 luaL_checktype(L, 2, LUA_TFUNCTION);
258 lua_pushstring(L, LUA_SIGNAL);
259 lua_gettable(L, LUA_REGISTRYINDEX);
261 lua_pushnumber(L, sig);
262 lua_pushvalue(L, 2);
263 lua_settable(L, -3);
265 /* Set the state for the handler */
266 Lsig = L;
268 if(lua_toboolean(L, 3)) { /* c hook? */
269 if(signal(sig, handle) == SIG_ERR) {
270 lua_pushboolean(L, 0);
271 } else {
272 lua_pushboolean(L, 1);
274 } else { /* lua_hook */
275 if(signal(sig, handle) == SIG_ERR) {
276 lua_pushboolean(L, 0);
277 } else {
278 lua_pushboolean(L, 1);
283 return 1;
287 * l_raise == raise(signal)
289 * signal = signal number or string
292 static int l_raise(lua_State *L) {
293 /* int args = lua_gettop(L); */
294 int t = 0; /* type */
295 lua_Number ret;
297 luaL_checkany(L, 1);
299 t = lua_type(L, 1);
301 if(t == LUA_TNUMBER) {
302 ret = (lua_Number) raise((int) lua_tonumber(L, 1));
303 lua_pushnumber(L, ret);
304 } else if(t == LUA_TSTRING) {
305 lua_pushstring(L, LUA_SIGNAL);
306 lua_gettable(L, LUA_REGISTRYINDEX);
307 lua_pushvalue(L, 1);
308 lua_gettable(L, -2);
310 if(!lua_isnumber(L, -1)) {
311 return luaL_error(L, "invalid signal string");
314 ret = (lua_Number) raise((int) lua_tonumber(L, -1));
315 lua_pop(L, 1); /* get rid of number we pushed */
316 lua_pushnumber(L, ret);
317 } else {
318 luaL_checknumber(L, 1); /* will always error, with good error msg */
321 return 1;
324 #if defined(__unix__) || defined(__APPLE__)
326 /* define some posix only functions */
329 * l_kill == kill(pid, signal)
331 * pid = process id
332 * signal = signal number or string
335 static int l_kill(lua_State *L) {
336 int t; /* type */
337 lua_Number ret; /* return value */
339 luaL_checknumber(L, 1); /* must be int for pid */
340 luaL_checkany(L, 2); /* check for a second arg */
342 t = lua_type(L, 2);
344 if(t == LUA_TNUMBER) {
345 ret = (lua_Number) kill((int) lua_tonumber(L, 1),
346 (int) lua_tonumber(L, 2));
347 lua_pushnumber(L, ret);
348 } else if(t == LUA_TSTRING) {
349 lua_pushstring(L, LUA_SIGNAL);
350 lua_gettable(L, LUA_REGISTRYINDEX);
351 lua_pushvalue(L, 2);
352 lua_gettable(L, -2);
354 if(!lua_isnumber(L, -1)) {
355 return luaL_error(L, "invalid signal string");
358 ret = (lua_Number) kill((int) lua_tonumber(L, 1),
359 (int) lua_tonumber(L, -1));
360 lua_pop(L, 1); /* get rid of number we pushed */
361 lua_pushnumber(L, ret);
362 } else {
363 luaL_checknumber(L, 2); /* will always error, with good error msg */
366 return 1;
369 #endif
371 static const struct luaL_Reg lsignal_lib[] = {
372 {"signal", l_signal},
373 {"raise", l_raise},
374 #if defined(__unix__) || defined(__APPLE__)
375 {"kill", l_kill},
376 #endif
377 {NULL, NULL}
380 int luaopen_util_signal(lua_State *L) {
381 #if (LUA_VERSION_NUM > 501)
382 luaL_checkversion(L);
383 #endif
384 int i = 0;
386 /* add the library */
387 lua_newtable(L);
388 luaL_setfuncs(L, lsignal_lib, 0);
390 /* push lua_signals table into the registry */
391 /* put the signals inside the library table too,
392 * they are only a reference */
393 lua_pushstring(L, LUA_SIGNAL);
394 lua_newtable(L);
396 while(lua_signals[i].name != NULL) {
397 /* registry table */
398 lua_pushstring(L, lua_signals[i].name);
399 lua_pushnumber(L, lua_signals[i].sig);
400 lua_settable(L, -3);
401 /* signal table */
402 lua_pushstring(L, lua_signals[i].name);
403 lua_pushnumber(L, lua_signals[i].sig);
404 lua_settable(L, -5);
405 i++;
408 /* add newtable to the registry */
409 lua_settable(L, LUA_REGISTRYINDEX);
411 return 1;