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