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