1 /* Handling of terminating signals. */
2 
3 /* in MT signals are handled in spvw.d:signal_handler_thread()*/
4 #if !defined(MULTITHREAD)
5 
6 /* --------------------------- Specification ----------------------------- */
7 
8 #if defined(HAVE_SIGNALS)
9 /* Installs the SIGTERM handler. */
10 local void install_sigterm_handler (void);
11 #endif
12 
13 /* --------------------------- Implementation ---------------------------- */
14 
15 #if defined(HAVE_SIGNALS)
16 
set_sigterm_handler(signal_handler_t handler)17 local void set_sigterm_handler (signal_handler_t handler) {
18   /* Iterate over those signals whose default action exits.
19      But do not install handlers for SIGABRT, SIGILL, SIGFPE, because these
20      signals indicate bugs, and a handler would make post-mortem debugging
21      (via core dump file) impossible. */
22 #ifdef SIGHUP
23   /* maybe ignore? No, use nohup instead */
24   SIGNAL(SIGHUP,handler);
25 #endif
26 #ifdef SIGQUIT
27   SIGNAL(SIGQUIT,handler);
28 #endif
29 #ifdef SIGKILL
30   SIGNAL(SIGKILL,handler);
31 #endif
32 #ifdef SIGTERM
33   SIGNAL(SIGTERM,handler);
34 #endif
35 }
36 
uninstall_sigterm_handler(void)37 local void uninstall_sigterm_handler (void) {
38   begin_system_call();
39   set_sigterm_handler(SIG_DFL);
40   end_system_call();
41 }
42 
43 
44 /* print the "exiting" message and quit */
quit_on_signal(int sig)45 local void quit_on_signal (int sig) {
46  #ifndef NO_ASYNC_INTERRUPTS
47   if (quit_on_signal_in_progress) { /* quit without much ado */
48     /* next signal will bypass this function and kill CLISP instantly: */
49     uninstall_sigterm_handler();
50     fprintf(stderr,GETTEXT("Signal %d while exiting on a signal; cleanup may be incomplete\n"),sig);
51     raise(sig);    /* kill CLISP instantly with the correct exit code */
52     return;        /* return from signal handler if the signal is blocked */
53   }
54   quit_on_signal_in_progress = true;
55   signal_handler_prepare_for_lisp(sig);
56   pushSTACK(Symbol_value(S(error_output))); fresh_line(&STACK_0);
57   pushSTACK(CLSTEXT("Exiting on signal ")); pushSTACK(STACK_1);
58   funcall(L(write_string),2);   /* (write-line "exiting" stderr) */
59   pushSTACK(sint_to_I(sig)); pushSTACK(STACK_1);
60   funcall(L(prin1),2);            /* (prin1 signal stderr) */
61   terpri(&STACK_0); skipSTACK(1); /* drop *error-output* */
62   final_exitcode = - sig;
63   quit();
64  #endif
65 }
66 
67 /* install error handlers for as many signals as possible */
install_sigterm_handler(void)68 local void install_sigterm_handler (void) {
69   set_sigterm_handler(&quit_on_signal);
70 #ifdef SIGTTOU
71   /* we must ignore SIGTTOU to avoid the following issue:
72       - when CLISP is running in the background,
73       - and its i/o is not redirected,
74       - and CLISP receives a terminating signal,
75      then CLISP will be stopped instead of being terminated
76      when it will try to write the "exiting..." message:
77   <http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap11.html>
78   <http://opengroup.org/onlinepubs/9699919799/basedefs/V1_chap11.html>
79          Attempts by a process in a background process group to write to
80          its controlling terminal shall cause the process group to be
81          sent a SIGTTOU signal */
82   SIGNAL(SIGTTOU,SIG_IGN);
83 #endif
84 }
85 #endif
86 #endif /* !MULTITHREAD */
87