usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / usbmodeswitch / jim / jim-signal.c
blob6a2a2bebb48b18ac15012302792172441fdb04f5
2 /*
3 * jim-signal.c
5 */
7 #include <signal.h>
8 #include <string.h>
9 #include <ctype.h>
10 #include <unistd.h>
12 #include "jim.h"
13 #include "jimautoconf.h"
14 #include "jim-subcmd.h"
15 #include "jim-signal.h"
17 #define MAX_SIGNALS (sizeof(jim_wide) * 8)
19 static jim_wide *sigloc;
20 static jim_wide sigsblocked;
21 static struct sigaction *sa_old;
22 static int signal_handling[MAX_SIGNALS];
24 /* Make sure to do this as a wide, not int */
25 #define sig_to_bit(SIG) ((jim_wide)1 << (SIG))
27 static void signal_handler(int sig)
29 /* We just remember which signals occurred. Jim_Eval() will
30 * notice this as soon as it can and throw an error
32 *sigloc |= sig_to_bit(sig);
35 static void signal_ignorer(int sig)
37 /* We just remember which signals occurred */
38 sigsblocked |= sig_to_bit(sig);
42 *----------------------------------------------------------------------
44 * Tcl_SignalId --
46 * Return a textual identifier for a signal number.
48 * Results:
49 * This procedure returns a machine-readable textual identifier
50 * that corresponds to sig. The identifier is the same as the
51 * #define name in signal.h.
53 * Side effects:
54 * None.
56 *----------------------------------------------------------------------
58 #define CHECK_SIG(NAME) if (sig == NAME) return #NAME
60 const char *Jim_SignalId(int sig)
62 CHECK_SIG(SIGABRT);
63 CHECK_SIG(SIGALRM);
64 CHECK_SIG(SIGBUS);
65 CHECK_SIG(SIGCHLD);
66 CHECK_SIG(SIGCONT);
67 CHECK_SIG(SIGFPE);
68 CHECK_SIG(SIGHUP);
69 CHECK_SIG(SIGILL);
70 CHECK_SIG(SIGINT);
71 #ifdef SIGIO
72 CHECK_SIG(SIGIO);
73 #endif
74 CHECK_SIG(SIGKILL);
75 CHECK_SIG(SIGPIPE);
76 CHECK_SIG(SIGPROF);
77 CHECK_SIG(SIGQUIT);
78 CHECK_SIG(SIGSEGV);
79 CHECK_SIG(SIGSTOP);
80 CHECK_SIG(SIGSYS);
81 CHECK_SIG(SIGTERM);
82 CHECK_SIG(SIGTRAP);
83 CHECK_SIG(SIGTSTP);
84 CHECK_SIG(SIGTTIN);
85 CHECK_SIG(SIGTTOU);
86 CHECK_SIG(SIGURG);
87 CHECK_SIG(SIGUSR1);
88 CHECK_SIG(SIGUSR2);
89 CHECK_SIG(SIGVTALRM);
90 CHECK_SIG(SIGWINCH);
91 CHECK_SIG(SIGXCPU);
92 CHECK_SIG(SIGXFSZ);
93 #ifdef SIGPWR
94 CHECK_SIG(SIGPWR);
95 #endif
96 #ifdef SIGCLD
97 CHECK_SIG(SIGCLD);
98 #endif
99 #ifdef SIGEMT
100 CHECK_SIG(SIGEMT);
101 #endif
102 #ifdef SIGLOST
103 CHECK_SIG(SIGLOST);
104 #endif
105 #ifdef SIGPOLL
106 CHECK_SIG(SIGPOLL);
107 #endif
108 #ifdef SIGINFO
109 CHECK_SIG(SIGINFO);
110 #endif
111 return "unknown signal";
114 const char *Jim_SignalName(int sig)
116 #ifdef HAVE_SYS_SIGLIST
117 if (sig >= 0 && sig < NSIG) {
118 return sys_siglist[sig];
120 #endif
121 return Jim_SignalId(sig);
125 * Given the name of a signal, returns the signal value if found,
126 * or returns -1 (and sets an error) if not found.
127 * We accept -SIGINT, SIGINT, INT or any lowercase version or a number,
128 * either positive or negative.
130 static int find_signal_by_name(Jim_Interp *interp, const char *name)
132 int i;
133 const char *pt = name;
135 /* Remove optional - and SIG from the front of the name */
136 if (*pt == '-') {
137 pt++;
139 if (strncasecmp(name, "sig", 3) == 0) {
140 pt += 3;
142 if (isdigit(UCHAR(pt[0]))) {
143 i = atoi(pt);
144 if (i > 0 && i < MAX_SIGNALS) {
145 return i;
148 else {
149 for (i = 1; i < MAX_SIGNALS; i++) {
150 /* Jim_SignalId() returns names such as SIGINT, and
151 * returns "unknown signal id" if unknown, so this will work
153 if (strcasecmp(Jim_SignalId(i) + 3, pt) == 0) {
154 return i;
158 Jim_SetResultString(interp, "unknown signal ", -1);
159 Jim_AppendString(interp, Jim_GetResult(interp), name, -1);
161 return -1;
164 #define SIGNAL_ACTION_HANDLE 1
165 #define SIGNAL_ACTION_IGNORE -1
166 #define SIGNAL_ACTION_DEFAULT 0
168 static int do_signal_cmd(Jim_Interp *interp, int action, int argc, Jim_Obj *const *argv)
170 struct sigaction sa;
171 int i;
173 if (argc == 0) {
174 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
175 for (i = 1; i < MAX_SIGNALS; i++) {
176 if (signal_handling[i] == action) {
177 /* Add signal name to the list */
178 Jim_ListAppendElement(interp, Jim_GetResult(interp),
179 Jim_NewStringObj(interp, Jim_SignalId(i), -1));
182 return JIM_OK;
185 /* Catch all the signals we care about */
186 if (action != SIGNAL_ACTION_DEFAULT) {
187 sa.sa_flags = 0;
188 sigemptyset(&sa.sa_mask);
189 if (action == SIGNAL_ACTION_HANDLE) {
190 sa.sa_handler = signal_handler;
192 else {
193 sa.sa_handler = signal_ignorer;
197 /* Iterate through the provided signals */
198 for (i = 0; i < argc; i++) {
199 int sig = find_signal_by_name(interp, Jim_String(argv[i]));
201 if (sig < 0) {
202 return JIM_ERR;
204 if (action != signal_handling[sig]) {
205 /* Need to change the action for this signal */
206 switch (action) {
207 case SIGNAL_ACTION_HANDLE:
208 case SIGNAL_ACTION_IGNORE:
209 if (signal_handling[sig] == SIGNAL_ACTION_DEFAULT) {
210 if (!sa_old) {
211 /* Allocate the structure the first time through */
212 sa_old = Jim_Alloc(sizeof(*sa_old) * MAX_SIGNALS);
214 sigaction(sig, &sa, &sa_old[sig]);
216 else {
217 sigaction(sig, &sa, 0);
219 break;
221 case SIGNAL_ACTION_DEFAULT:
222 /* Restore old handler */
223 if (sa_old) {
224 sigaction(sig, &sa_old[sig], 0);
227 signal_handling[sig] = action;
231 return JIM_OK;
234 static int signal_cmd_handle(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
236 return do_signal_cmd(interp, SIGNAL_ACTION_HANDLE, argc, argv);
239 static int signal_cmd_ignore(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
241 return do_signal_cmd(interp, SIGNAL_ACTION_IGNORE, argc, argv);
244 static int signal_cmd_default(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
246 return do_signal_cmd(interp, SIGNAL_ACTION_DEFAULT, argc, argv);
249 static int signal_set_sigmask_result(Jim_Interp *interp, jim_wide sigmask)
251 int i;
252 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
254 for (i = 0; i < MAX_SIGNALS; i++) {
255 if (sigmask & sig_to_bit(i)) {
256 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, Jim_SignalId(i), -1));
259 Jim_SetResult(interp, listObj);
260 return JIM_OK;
263 static int signal_cmd_check(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
265 int clear = 0;
266 jim_wide mask = 0;
267 jim_wide blocked;
269 if (argc > 0 && Jim_CompareStringImmediate(interp, argv[0], "-clear")) {
270 clear++;
272 if (argc > clear) {
273 int i;
275 /* Signals specified */
276 for (i = clear; i < argc; i++) {
277 int sig = find_signal_by_name(interp, Jim_String(argv[i]));
279 if (sig < 0 || sig >= MAX_SIGNALS) {
280 return -1;
282 mask |= sig_to_bit(sig);
285 else {
286 /* No signals specified, so check/clear all */
287 mask = ~mask;
290 if ((sigsblocked & mask) == 0) {
291 /* No matching signals, so empty result and nothing to do */
292 return JIM_OK;
294 /* Be careful we don't have a race condition where signals are cleared but not returned */
295 blocked = sigsblocked & mask;
296 if (clear) {
297 sigsblocked &= ~blocked;
299 /* Set the result */
300 signal_set_sigmask_result(interp, blocked);
301 return JIM_OK;
304 static int signal_cmd_throw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
306 int sig = SIGINT;
308 if (argc == 1) {
309 if ((sig = find_signal_by_name(interp, Jim_String(argv[0]))) < 0) {
310 return JIM_ERR;
314 /* If the signal is ignored (blocked) ... */
315 if (signal_handling[sig] == SIGNAL_ACTION_IGNORE) {
316 sigsblocked |= sig_to_bit(sig);
317 return JIM_OK;
320 /* Just set the signal */
321 interp->sigmask |= sig_to_bit(sig);
323 /* Set the canonical name of the signal as the result */
324 Jim_SetResultString(interp, Jim_SignalId(sig), -1);
326 /* And simply say we caught the signal */
327 return JIM_SIGNAL;
331 *-----------------------------------------------------------------------------
333 * Jim_SignalCmd --
334 * Implements the TCL signal command:
335 * signal handle|ignore|default|throw ?signals ...?
336 * signal throw signal
338 * Specifies which signals are handled by Tcl code.
339 * If the one of the given signals is caught, it causes a JIM_SIGNAL
340 * exception to be thrown which can be caught by catch.
342 * Use 'signal ignore' to ignore the signal(s)
343 * Use 'signal default' to go back to the default behaviour
344 * Use 'signal throw signal' to raise the given signal
346 * If no arguments are given, returns the list of signals which are being handled
348 * Results:
349 * Standard TCL results.
351 *-----------------------------------------------------------------------------
353 static const jim_subcmd_type signal_command_table[] = {
354 { .cmd = "handle",
355 .args = "?signals ...?",
356 .function = signal_cmd_handle,
357 .minargs = 0,
358 .maxargs = -1,
359 .description = "Lists handled signals, or adds to handled signals"
361 { .cmd = "ignore",
362 .args = "?signals ...?",
363 .function = signal_cmd_ignore,
364 .minargs = 0,
365 .maxargs = -1,
366 .description = "Lists ignored signals, or adds to ignored signals"
368 { .cmd = "default",
369 .args = "?signals ...?",
370 .function = signal_cmd_default,
371 .minargs = 0,
372 .maxargs = -1,
373 .description = "Lists defaulted signals, or adds to defaulted signals"
375 { .cmd = "check",
376 .args = "?-clear? ?signals ...?",
377 .function = signal_cmd_check,
378 .minargs = 0,
379 .maxargs = -1,
380 .description = "Returns ignored signals which have occurred, and optionally clearing them"
382 { .cmd = "throw",
383 .args = "?signal?",
384 .function = signal_cmd_throw,
385 .minargs = 0,
386 .maxargs = 1,
387 .description = "Raises the given signal (default SIGINT)"
389 { 0 }
392 static int Jim_AlarmCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
394 int ret;
396 if (argc != 2) {
397 Jim_WrongNumArgs(interp, 1, argv, "seconds");
398 return JIM_ERR;
400 else {
401 #ifdef HAVE_UALARM
402 double t;
404 ret = Jim_GetDouble(interp, argv[1], &t);
405 if (ret == JIM_OK) {
406 if (t < 1) {
407 ualarm(t * 1e6, 0);
409 else {
410 alarm(t);
413 #else
414 long t;
416 ret = Jim_GetLong(interp, argv[1], &t);
417 if (ret == JIM_OK) {
418 alarm(t);
420 #endif
423 return ret;
426 static int Jim_SleepCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
428 int ret;
430 if (argc != 2) {
431 Jim_WrongNumArgs(interp, 1, argv, "seconds");
432 return JIM_ERR;
434 else {
435 double t;
437 ret = Jim_GetDouble(interp, argv[1], &t);
438 if (ret == JIM_OK) {
439 #ifdef HAVE_USLEEP
440 if (t < 1) {
441 usleep(t * 1e6);
443 else
444 #endif
445 sleep(t);
449 return ret;
452 static int Jim_KillCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
454 int sig;
455 long pid;
456 Jim_Obj *pidObj;
457 const char *signame;
459 if (argc != 2 && argc != 3) {
460 Jim_WrongNumArgs(interp, 1, argv, "?SIG|-0? pid");
461 return JIM_ERR;
464 if (argc == 2) {
465 signame = "SIGTERM";
466 pidObj = argv[1];
468 else {
469 signame = Jim_String(argv[1]);
470 pidObj = argv[2];
473 /* Special 'kill -0 pid' to determine if a pid exists */
474 if (strcmp(signame, "-0") == 0 || strcmp(signame, "0") == 0) {
475 sig = 0;
477 else {
478 sig = find_signal_by_name(interp, signame);
479 if (sig < 0) {
480 return JIM_ERR;
484 if (Jim_GetLong(interp, pidObj, &pid) != JIM_OK) {
485 return JIM_ERR;
488 if (kill(pid, sig) == 0) {
489 return JIM_OK;
492 Jim_SetResultString(interp, "kill: Failed to deliver signal", -1);
493 return JIM_ERR;
496 int Jim_signalInit(Jim_Interp *interp)
498 if (Jim_PackageProvide(interp, "signal", "1.0", JIM_ERRMSG))
499 return JIM_ERR;
501 /* Teach the jim core how to set a result from a sigmask */
502 interp->signal_set_result = signal_set_sigmask_result;
504 /* Make sure we know where to store the signals which occur */
505 sigloc = &interp->sigmask;
507 Jim_CreateCommand(interp, "signal", Jim_SubCmdProc, (void *)signal_command_table, NULL);
508 Jim_CreateCommand(interp, "alarm", Jim_AlarmCmd, 0, 0);
509 Jim_CreateCommand(interp, "kill", Jim_KillCmd, 0, 0);
511 /* Sleep is slightly dubious here */
512 Jim_CreateCommand(interp, "sleep", Jim_SleepCmd, 0, 0);
513 return JIM_OK;