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