73f721917e4e4748c5c5cb50a60730ce29669fca
[tinc] / signal.c
1 /*
2     signal.c -- signal handling
3     Copyright (C) 2012-2022 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "event.h"
23
24 // From Matz's Ruby
25 #ifndef NSIG
26 # define NSIG (_SIGMAX + 1)      /* For QNX */
27 #endif
28
29 static io_t signalio;
30 static int pipefd[2] = {-1, -1};
31 static signal_t *signal_handle[NSIG + 1] = {NULL};
32
33 static void signal_handler(int signum) {
34         unsigned char num = signum;
35
36         if(write(pipefd[1], &num, 1) != 1) {
37                 // Pipe full or broken, nothing we can do about it.
38         }
39 }
40
41 static void signalio_handler(void *data, int flags) {
42         (void)data;
43         (void)flags;
44         unsigned char signum;
45
46         if(read(pipefd[0], &signum, 1) != 1) {
47                 return;
48         }
49
50         signal_t *sig = signal_handle[signum];
51
52         if(sig) {
53                 sig->cb(sig->data);
54         }
55 }
56
57 static void pipe_init(void) {
58         if(!pipe(pipefd)) {
59                 io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
60         }
61 }
62
63 void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
64         if(sig->cb) {
65                 return;
66         }
67
68         sig->signum = signum;
69         sig->cb = cb;
70         sig->data = data;
71
72         if(pipefd[0] == -1) {
73                 pipe_init();
74         }
75
76         signal(signum, signal_handler);
77
78         signal_handle[signum] = sig;
79 }
80
81 void signal_del(signal_t *sig) {
82         if(!sig->cb) {
83                 return;
84         }
85
86         signal(sig->signum, SIG_DFL);
87
88         signal_handle[sig->signum] = NULL;
89         sig->cb = NULL;
90 }