1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2016-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // These functions may be provided by gnulib.  We don't include gnulib
27 // headers directly in Octave's C++ source files to avoid problems that
28 // may be caused by the way that gnulib overrides standard library
29 // functions.
30 
31 #if defined (HAVE_CONFIG_H)
32 #  include "config.h"
33 #endif
34 
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #if defined (__WIN32__) && ! defined (__CYGWIN__)
42 #  include <windows.h>
43 #else
44 #  include <pthread.h>
45 #endif
46 
47 #include "signal-wrappers.h"
48 
49 int
octave_kill_wrapper(pid_t pid,int signum)50 octave_kill_wrapper (pid_t pid, int signum)
51 {
52 #if defined (HAVE_KILL)
53   return kill (pid, signum);
54 #else
55 
56   octave_unused_parameter (pid);
57   octave_unused_parameter (signum);
58 
59   return -1;
60 #endif
61 }
62 
63 char *
octave_strsignal_wrapper(int signum)64 octave_strsignal_wrapper (int signum)
65 {
66   return strsignal (signum);
67 }
68 
69 bool
octave_have_kill(void)70 octave_have_kill (void)
71 {
72 #if defined (HAVE_KILL)
73   return true;
74 #else
75   return false;
76 #endif
77 }
78 
79 bool
octave_get_sig_number(const char * signame,int * signum)80 octave_get_sig_number (const char *signame, int *signum)
81 {
82   *signum = -1;
83 
84   // FIXME: this should probably use a perfect hash function.
85 
86   if (! strcmp (signame, "SIGINT"))
87     {
88 #if defined (SIGINT)
89       *signum = SIGINT;
90       return true;
91 #endif
92     }
93   else if (! strcmp (signame, "SIGBREAK"))
94     {
95 #if defined (SIGBREAK)
96       *signum = SIGBREAK;
97       return true;
98 #endif
99     }
100   else if (! strcmp (signame, "SIGABRT"))
101     {
102 #if defined (SIGABRT)
103       *signum = SIGABRT;
104       return true;
105 #endif
106     }
107   else if (! strcmp (signame, "SIGALRM"))
108     {
109 #if defined (SIGALRM)
110       *signum = SIGALRM;
111       return true;
112 #endif
113     }
114   else if (! strcmp (signame, "SIGBUS"))
115     {
116 #if defined (SIGBUS)
117       *signum = SIGBUS;
118       return true;
119 #endif
120     }
121   else if (! strcmp (signame, "SIGCHLD"))
122     {
123 #if defined (SIGCHLD)
124       *signum = SIGCHLD;
125       return true;
126 #endif
127     }
128   else if (! strcmp (signame, "SIGCLD"))
129     {
130 #if defined (SIGCLD)
131       *signum = SIGCLD;
132       return true;
133 #endif
134     }
135   else if (! strcmp (signame, "SIGCONT"))
136     {
137 #if defined (SIGCONT)
138       *signum = SIGCONT;
139       return true;
140 #endif
141     }
142   else if (! strcmp (signame, "SIGEMT"))
143     {
144 #if defined (SIGEMT)
145       *signum = SIGEMT;
146       return true;
147 #endif
148     }
149   else if (! strcmp (signame, "SIGFPE"))
150     {
151 #if defined (SIGFPE)
152       *signum = SIGFPE;
153       return true;
154 #endif
155     }
156   else if (! strcmp (signame, "SIGHUP"))
157     {
158 #if defined (SIGHUP)
159       *signum = SIGHUP;
160       return true;
161 #endif
162     }
163   else if (! strcmp (signame, "SIGILL"))
164     {
165 #if defined (SIGILL)
166       *signum = SIGILL;
167       return true;
168 #endif
169     }
170   else if (! strcmp (signame, "SIGINFO"))
171     {
172 #if defined (SIGINFO)
173       *signum = SIGINFO;
174       return true;
175 #endif
176     }
177   else if (! strcmp (signame, "SIGIOT"))
178     {
179 #if defined (SIGIOT)
180       *signum = SIGIOT;
181       return true;
182 #endif
183     }
184   else if (! strcmp (signame, "SIGKILL"))
185     {
186 #if defined (SIGKILL)
187       *signum = SIGKILL;
188       return true;
189 #endif
190     }
191   else if (! strcmp (signame, "SIGLOST"))
192     {
193 #if defined (SIGLOST)
194       *signum = SIGLOST;
195       return true;
196 #endif
197     }
198   else if (! strcmp (signame, "SIGPIPE"))
199     {
200 #if defined (SIGPIPE)
201       *signum = SIGPIPE;
202       return true;
203 #endif
204     }
205   else if (! strcmp (signame, "SIGPOLL"))
206     {
207 #if defined (SIGPOLL)
208       *signum = SIGPOLL;
209       return true;
210 #endif
211     }
212   else if (! strcmp (signame, "SIGPROF"))
213     {
214 #if defined (SIGPROF)
215       *signum = SIGPROF;
216       return true;
217 #endif
218     }
219   else if (! strcmp (signame, "SIGPWR"))
220     {
221 #if defined (SIGPWR)
222       *signum = SIGPWR;
223       return true;
224 #endif
225     }
226   else if (! strcmp (signame, "SIGQUIT"))
227     {
228 #if defined (SIGQUIT)
229       *signum = SIGQUIT;
230       return true;
231 #endif
232     }
233   else if (! strcmp (signame, "SIGSEGV"))
234     {
235 #if defined (SIGSEGV)
236       *signum = SIGSEGV;
237       return true;
238 #endif
239     }
240   else if (! strcmp (signame, "SIGSTOP"))
241     {
242 #if defined (SIGSTOP)
243       *signum = SIGSTOP;
244       return true;
245 #endif
246     }
247   else if (! strcmp (signame, "SIGSYS"))
248     {
249 #if defined (SIGSYS)
250       *signum = SIGSYS;
251       return true;
252 #endif
253     }
254   else if (! strcmp (signame, "SIGTERM"))
255     {
256 #if defined (SIGTERM)
257       *signum = SIGTERM;
258       return true;
259 #endif
260     }
261   else if (! strcmp (signame, "SIGTRAP"))
262     {
263 #if defined (SIGTRAP)
264       *signum = SIGTRAP;
265       return true;
266 #endif
267     }
268   else if (! strcmp (signame, "SIGTSTP"))
269     {
270 #if defined (SIGTSTP)
271       *signum = SIGTSTP;
272       return true;
273 #endif
274     }
275   else if (! strcmp (signame, "SIGTTIN"))
276     {
277 #if defined (SIGTTIN)
278       *signum = SIGTTIN;
279       return true;
280 #endif
281     }
282   else if (! strcmp (signame, "SIGTTOU"))
283     {
284 #if defined (SIGTTOU)
285       *signum = SIGTTOU;
286       return true;
287 #endif
288     }
289   else if (! strcmp (signame, "SIGURG"))
290     {
291 #if defined (SIGURG)
292       *signum = SIGURG;
293       return true;
294 #endif
295     }
296   else if (! strcmp (signame, "SIGUSR1"))
297     {
298 #if defined (SIGUSR1)
299       *signum = SIGUSR1;
300       return true;
301 #endif
302     }
303   else if (! strcmp (signame, "SIGUSR2"))
304     {
305 #if defined (SIGUSR2)
306       *signum = SIGUSR2;
307       return true;
308 #endif
309     }
310   else if (! strcmp (signame, "SIGVTALRM"))
311     {
312 #if defined (SIGVTALRM)
313       *signum = SIGVTALRM;
314       return true;
315 #endif
316     }
317   else if (! strcmp (signame, "SIGIO"))
318     {
319 #if defined (SIGIO)
320       *signum = SIGIO;
321       return true;
322 #endif
323     }
324   else if (! strcmp (signame, "SIGWINCH"))
325     {
326 #if defined (SIGWINCH)
327       *signum = SIGWINCH;
328       return true;
329 #endif
330     }
331   else if (! strcmp (signame, "SIGXCPU"))
332     {
333 #if defined (SIGXCPU)
334       *signum = SIGXCPU;
335       return true;
336 #endif
337     }
338   else if (! strcmp (signame, "SIGXFSZ"))
339     {
340 #if defined (SIGXFSZ)
341       *signum = SIGXFSZ;
342       return true;
343 #endif
344     }
345 
346   return false;
347 }
348 
349 octave_sig_handler *
octave_set_signal_handler_internal(int sig,octave_sig_handler * handler,bool restart_syscalls)350 octave_set_signal_handler_internal (int sig, octave_sig_handler *handler,
351                                     bool restart_syscalls)
352 {
353   struct sigaction act, oact;
354 
355   act.sa_handler = handler;
356   act.sa_flags = 0;
357 
358 #if defined (SIGALRM)
359   if (sig == SIGALRM)
360     {
361 #  if defined (SA_INTERRUPT)
362       act.sa_flags |= SA_INTERRUPT;
363 #  endif
364     }
365 #endif
366 #if defined (SA_RESTART)
367 #  if defined (SIGALRM)
368   else
369 #  endif
370   // FIXME: Do we also need to explicitly disable SA_RESTART?
371   if (restart_syscalls)
372     act.sa_flags |= SA_RESTART;
373 #endif
374 
375   sigemptyset (&act.sa_mask);
376   sigemptyset (&oact.sa_mask);
377 
378   sigaction (sig, &act, &oact);
379 
380   return oact.sa_handler;
381 }
382 
383 octave_sig_handler *
octave_set_signal_handler_by_name(const char * signame,octave_sig_handler * handler,bool restart_syscalls)384 octave_set_signal_handler_by_name (const char *signame,
385                                    octave_sig_handler *handler,
386                                    bool restart_syscalls)
387 {
388   int sig;
389 
390   return (octave_get_sig_number (signame, &sig)
391           ? octave_set_signal_handler_internal (sig, handler, restart_syscalls)
392           : 0);
393 }
394 
395 octave_sig_handler *
octave_set_default_signal_handler(int sig)396 octave_set_default_signal_handler (int sig)
397 {
398   return octave_set_signal_handler_internal (sig, SIG_DFL, true);
399 }
400 
401 octave_sig_handler *
octave_set_default_signal_handler_by_name(const char * signame)402 octave_set_default_signal_handler_by_name (const char *signame)
403 {
404   return octave_set_signal_handler_by_name (signame, SIG_DFL, true);
405 }
406 
407 int
octave_num_signals(void)408 octave_num_signals (void)
409 {
410   return NSIG;
411 }
412 
413 typedef struct
414 {
415   sigset_t nvar;
416   sigset_t ovar;
417 } sigset_info;
418 
419 void *
octave_block_child(void)420 octave_block_child (void)
421 {
422 #if defined (SIGCHLD) || defined (SIGCLD)
423 
424   sigset_info *context = (sigset_info *) malloc (sizeof (sigset_info));
425 
426   if (context)
427     {
428       sigemptyset (&(context->ovar));
429       sigemptyset (&(context->nvar));
430 #if defined (SIGCHLD)
431       sigaddset (&(context->nvar), SIGCHLD);
432 #endif
433 #if defined (SIGCLD)
434       sigaddset (&(context->nvar), SIGCLD);
435 #endif
436       sigprocmask (SIG_BLOCK, &(context->nvar), &(context->ovar));
437     }
438 
439   return context;
440 
441 #else
442 
443   return 0;
444 
445 #endif
446 }
447 
448 void
octave_unblock_child(void * context_arg)449 octave_unblock_child (void *context_arg)
450 {
451   if (context_arg)
452     {
453       sigset_info *context = (sigset_info *) context_arg;
454 
455       sigprocmask (SIG_SETMASK, &(context->ovar), 0);
456 
457       free (context);
458     }
459 }
460 
461 static void
block_or_unblock_signal(int how,int sig)462 block_or_unblock_signal (int how, int sig)
463 {
464 #if ! defined (__WIN32__) || defined (__CYGWIN__)
465 
466   // Blocking/unblocking signals at thread level is only supported
467   // on platform with fully compliant POSIX threads. This is not
468   // supported on Win32. Moreover, we have to make sure that SIGINT
469   // handler is not installed before calling AllocConsole: installing
470   // a SIGINT handler internally calls SetConsoleCtrlHandler, which
471   // must be called after AllocConsole to be effective.
472 
473   sigset_t signal_mask;
474 
475   sigemptyset (&signal_mask);
476 
477   sigaddset (&signal_mask, sig);
478 
479   pthread_sigmask (how, &signal_mask, 0);
480 
481 #else
482 
483   octave_unused_parameter (how);
484   octave_unused_parameter (sig);
485 
486 #endif
487 }
488 
489 void
octave_block_interrupt_signal(void)490 octave_block_interrupt_signal (void)
491 {
492   block_or_unblock_signal (SIG_BLOCK, SIGINT);
493 
494 #if defined (SIGBREAK)
495   block_or_unblock_signal (SIG_BLOCK, SIGBREAK);
496 #endif
497 }
498 
499 void
octave_unblock_interrupt_signal(void)500 octave_unblock_interrupt_signal (void)
501 {
502   block_or_unblock_signal (SIG_UNBLOCK, SIGINT);
503 
504 #if defined (SIGBREAK)
505   block_or_unblock_signal (SIG_UNBLOCK, SIGBREAK);
506 #endif
507 }
508 
509 static void
block_or_unblock_signal_by_name(int how,const char * signame)510 block_or_unblock_signal_by_name (int how, const char *signame)
511 {
512   int sig;
513 
514   if (octave_get_sig_number (signame, &sig))
515     block_or_unblock_signal (how, sig);
516 }
517 
518 void
octave_block_signal_by_name(const char * signame)519 octave_block_signal_by_name (const char *signame)
520 {
521   block_or_unblock_signal_by_name (SIG_BLOCK, signame);
522 }
523 
524 void
octave_unblock_signal_by_name(const char * signame)525 octave_unblock_signal_by_name (const char *signame)
526 {
527   block_or_unblock_signal_by_name (SIG_UNBLOCK, signame);
528 }
529 
530 /* Allow us to save the signal mask and then restore it to the most
531    recently saved value.  This is necessary when using the POSIX signal
532    handling interface on some systems calling longjmp out of the signal
533    handler to get to the top level on an interrupt doesn't restore the
534    original signal mask.  Alternatively, we could use
535    sigsetjmp/siglongjmp, but saving and restoring the signal mask
536    ourselves works ok and seems simpler just now.  */
537 
538 static sigset_t octave_signal_mask;
539 
540 void
octave_save_signal_mask(void)541 octave_save_signal_mask (void)
542 {
543   sigprocmask (0, 0, &octave_signal_mask);
544 }
545 
546 void
octave_restore_signal_mask(void)547 octave_restore_signal_mask (void)
548 {
549   sigprocmask (SIG_SETMASK, &octave_signal_mask, 0);
550 }
551 
552 void *
octave_alloc_signal_mask(void)553 octave_alloc_signal_mask (void)
554 {
555   return malloc (sizeof (sigset_t));
556 }
557 
558 void
octave_free_signal_mask(void * mask)559 octave_free_signal_mask (void *mask)
560 {
561   free (mask);
562 }
563 
564 void
octave_get_signal_mask(void * mask)565 octave_get_signal_mask (void *mask)
566 {
567   sigprocmask (0, 0, mask);
568 }
569 
570 void
octave_set_signal_mask(void * mask)571 octave_set_signal_mask (void *mask)
572 {
573   sigprocmask (SIG_SETMASK, (sigset_t *) mask, 0);
574 }
575 
576 #if ! defined (__WIN32__)
577 static const sigset_t *
octave_async_signals(void)578 octave_async_signals (void)
579 {
580   static bool initialized = false;
581   static sigset_t sigmask;
582 
583   if (! initialized)
584     {
585       sigemptyset (&sigmask);
586 
587       // The signals listed here should match the list of signals that
588       // we handle in the signal handler thread.
589 
590       // Interrupt signals.
591 
592 #if defined (SIGINT)
593       sigaddset (&sigmask, SIGINT);
594 #endif
595 
596 #if defined (SIGBREAK)
597       sigaddset (&sigmask, SIGBREAK);
598 #endif
599 
600       // Termination signals.
601 
602 #if defined (SIGHUP)
603       sigaddset (&sigmask, SIGHUP);
604 #endif
605 
606 #if defined (SIGQUIT)
607       sigaddset (&sigmask, SIGQUIT);
608 #endif
609 
610 #if defined (SIGTERM)
611       sigaddset (&sigmask, SIGTERM);
612 #endif
613 
614       // Alarm signals.
615 
616 #if defined (SIGALRM)
617       sigaddset (&sigmask, SIGALRM);
618 #endif
619 
620 #if defined (SIGVTALRM)
621       sigaddset (&sigmask, SIGVTALRM);
622 #endif
623 
624       // I/O signals.
625 
626 #if defined (SIGLOST)
627       sigaddset (&sigmask, SIGLOST);
628 #endif
629 
630 #if defined (SIGPIPE)
631       sigaddset (&sigmask, SIGPIPE);
632 #endif
633 
634       // Job control signals.
635 
636 #if defined (SIGCHLD)
637       sigaddset (&sigmask, SIGCHLD);
638 #endif
639 
640 #if defined (SIGCLD)
641       sigaddset (&sigmask, SIGCLD);
642 #endif
643 
644       // Resource limit signals.
645 
646 #if defined (SIGXCPU)
647       sigaddset (&sigmask, SIGXCPU);
648 #endif
649 
650 #if defined (SIGXFSZ)
651       sigaddset (&sigmask, SIGXFSZ);
652 #endif
653 
654       initialized = true;
655     }
656 
657   return &sigmask;
658 }
659 #endif
660 
661 void
octave_block_async_signals(void)662 octave_block_async_signals (void)
663 {
664 #if ! defined (__WIN32__) || defined (__CYGWIN__)
665   pthread_sigmask (SIG_BLOCK, octave_async_signals (), 0);
666 #endif
667 }
668 
669 void
octave_unblock_async_signals(void)670 octave_unblock_async_signals (void)
671 {
672 #if ! defined (__WIN32__) || defined (__CYGWIN__)
673   pthread_sigmask (SIG_UNBLOCK, octave_async_signals (), 0);
674 #endif
675 }
676 
677 int
octave_raise_wrapper(int signum)678 octave_raise_wrapper (int signum)
679 {
680   return raise (signum);
681 }
682 
683 #if ! defined (__WIN32__)
684 static void *
signal_watcher(void * arg)685 signal_watcher (void *arg)
686 {
687   octave_sig_handler *handler = (octave_sig_handler *) arg;
688 
689   octave_unblock_async_signals ();
690 
691   const sigset_t *async_signals = octave_async_signals ();
692 
693   while (1)
694     {
695       int sig_caught;
696 
697       if (sigwait (async_signals, &sig_caught))
698         {
699           // FIXME: what else should we do?
700           abort ();
701         }
702 
703       // Let handler have complete control over what to do.
704       (*handler) (sig_caught);
705     }
706 }
707 #endif
708 
709 void
octave_create_interrupt_watcher_thread(octave_sig_handler * handler)710 octave_create_interrupt_watcher_thread (octave_sig_handler *handler)
711 {
712 #if ! defined (__WIN32__)
713   pthread_t sighandler_thread_id;
714 
715   if (pthread_create (&sighandler_thread_id, 0, signal_watcher, handler))
716     {
717       // FIXME: what else should we do?
718       abort ();
719     }
720 #else
721   octave_unblock_async_signals ();
722 
723   octave_unused_parameter (handler);
724 #endif
725 }
726 
727 #if ! defined (__WIN32__)
728 static void
print_sigset(FILE * of,const char * prefix,const sigset_t * sigset)729 print_sigset (FILE *of, const char *prefix, const sigset_t *sigset)
730 {
731   int sig;
732   int cnt = 0;
733 
734   for (sig = 1; sig < NSIG; sig++)
735     {
736       if (sigismember (sigset, sig))
737         {
738           cnt++;
739           fprintf (of, "%ld: %s%d (%s)\n", (long int) pthread_self (),
740                    prefix, sig, strsignal (sig));
741         }
742     }
743 
744   if (cnt == 0)
745     fprintf (of, "%ld: %s<empty signal set>\n", (long int) pthread_self (),
746              prefix);
747 }
748 
749 static int
print_sigmask(FILE * of,const char * msg)750 print_sigmask (FILE *of, const char *msg)
751 {
752   sigset_t sigmask;
753 
754   if (msg)
755     fprintf (of, "%s", msg);
756 
757   if (pthread_sigmask (SIG_BLOCK, NULL, &sigmask) == -1)
758     return -1;
759 
760   print_sigset (of, "\t\t", &sigmask);
761 
762   return 0;
763 }
764 #endif
765 
766 void
octave_show_sigmask(const char * msg)767 octave_show_sigmask (const char *msg)
768 {
769 #if ! defined (__WIN32__)
770   if (! msg)
771     msg = "signal mask\n";
772 
773   print_sigmask (stderr, msg);
774 #else
775   octave_unused_parameter (msg);
776 
777   fputs ("no signal mask on Windows systems\n", stderr);
778 #endif
779 }
780