1 /*        $NetBSD: syssignal.c,v 1.6 2020/05/25 20:47:24 christos Exp $         */
2 
3 #ifdef HAVE_CONFIG_H
4 # include <config.h>
5 #endif
6 
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <signal.h>
10 
11 #include "ntp_syslog.h"
12 #include "ntp_stdlib.h"
13 
14 static ctrl_c_fn    ctrl_c_hook;
15 #ifndef SYS_WINNT
16 RETSIGTYPE sigint_handler(int);
17 #else
18 BOOL WINAPI console_event_handler(DWORD);
19 #endif
20 
21 
22 #ifdef HAVE_SIGACTION
23 
24 # ifdef SA_RESTART
25 #  define Z_SA_RESTART                  SA_RESTART
26 # else
27 #  define Z_SA_RESTART                  0
28 # endif
29 
30 void
signal_no_reset(int sig,void (* func)(int))31 signal_no_reset(
32           int sig,
33           void (*func)(int)
34           )
35 {
36           int n;
37           struct sigaction vec;
38           struct sigaction ovec;
39 
40           ZERO(vec);
41           sigemptyset(&vec.sa_mask);
42           vec.sa_handler = func;
43 
44           /* Added for PPS clocks on Solaris 7 which get EINTR errors */
45 # ifdef SIGPOLL
46           if (SIGPOLL == sig)
47                     vec.sa_flags = Z_SA_RESTART;
48 # endif
49 # ifdef SIGIO
50           if (SIGIO == sig)
51                     vec.sa_flags = Z_SA_RESTART;
52 # endif
53 
54           do
55                     n = sigaction(sig, &vec, &ovec);
56           while (-1 == n && EINTR == errno);
57           if (-1 == n) {
58                     perror("sigaction");
59                     exit(1);
60           }
61 }
62 
63 #elif  HAVE_SIGVEC
64 
65 void
signal_no_reset(int sig,RETSIGTYPE (* func)(int))66 signal_no_reset(
67           int sig,
68           RETSIGTYPE (*func)(int)
69           )
70 {
71           struct sigvec sv;
72           int n;
73 
74           ZERO(sv);
75           sv.sv_handler = func;
76           n = sigvec(sig, &sv, (struct sigvec *)NULL);
77           if (-1 == n) {
78                     perror("sigvec");
79                     exit(1);
80           }
81 }
82 
83 #elif  HAVE_SIGSET
84 
85 void
signal_no_reset(int sig,RETSIGTYPE (* func)(int))86 signal_no_reset(
87           int sig,
88           RETSIGTYPE (*func)(int)
89           )
90 {
91           int n;
92 
93           n = sigset(sig, func);
94           if (-1 == n) {
95                     perror("sigset");
96                     exit(1);
97           }
98 }
99 
100 #else
101 
102 /* Beware!          This implementation resets the signal to SIG_DFL */
103 void
signal_no_reset(int sig,RETSIGTYPE (* func)(int))104 signal_no_reset(
105           int sig,
106           RETSIGTYPE (*func)(int)
107           )
108 {
109 #ifndef SIG_ERR
110 # define SIG_ERR    (-1)
111 #endif
112           if (SIG_ERR == signal(sig, func)) {
113                     perror("signal");
114                     exit(1);
115           }
116 }
117 
118 #endif
119 
120 #ifndef SYS_WINNT
121 /*
122  * POSIX implementation of set_ctrl_c_hook()
123  */
124 RETSIGTYPE
sigint_handler(int signum)125 sigint_handler(
126           int       signum
127           )
128 {
129           UNUSED_ARG(signum);
130           if (ctrl_c_hook != NULL)
131                     (*ctrl_c_hook)();
132 }
133 
134 void
set_ctrl_c_hook(ctrl_c_fn c_hook)135 set_ctrl_c_hook(
136           ctrl_c_fn c_hook
137           )
138 {
139           RETSIGTYPE (*handler)(int);
140 
141           if (NULL == c_hook) {
142                     handler = SIG_DFL;
143                     signal_no_reset(SIGINT, handler);
144                     ctrl_c_hook = c_hook;
145           } else {
146                     ctrl_c_hook = c_hook;
147                     handler = &sigint_handler;
148                     signal_no_reset(SIGINT, handler);
149           }
150 }
151 #else     /* SYS_WINNT follows */
152 /*
153  * Windows implementation of set_ctrl_c_hook()
154  */
155 BOOL WINAPI
console_event_handler(DWORD dwCtrlType)156 console_event_handler(
157           DWORD     dwCtrlType
158           )
159 {
160           BOOL handled;
161 
162           if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
163                     (*ctrl_c_hook)();
164                     handled = TRUE;
165           } else {
166                     handled = FALSE;
167           }
168 
169           return handled;
170 }
171 void
set_ctrl_c_hook(ctrl_c_fn c_hook)172 set_ctrl_c_hook(
173           ctrl_c_fn c_hook
174           )
175 {
176           BOOL install;
177 
178           if (NULL == c_hook) {
179                     ctrl_c_hook = NULL;
180                     install = FALSE;
181           } else {
182                     ctrl_c_hook = c_hook;
183                     install = TRUE;
184           }
185           if (!SetConsoleCtrlHandler(&console_event_handler, install))
186                     msyslog(LOG_ERR, "Can't %s console control handler: %m",
187                               (install)
188                                   ? "add"
189                                   : "remove");
190 }
191 #endif    /* SYS_WINNT */
192