154359Sroberto#ifdef HAVE_CONFIG_H
254359Sroberto# include <config.h>
354359Sroberto#endif
454359Sroberto
554359Sroberto#include <stdio.h>
654359Sroberto#include <sys/types.h>
754359Sroberto#include <signal.h>
854359Sroberto
954359Sroberto#include "ntp_syslog.h"
1054359Sroberto#include "ntp_stdlib.h"
1154359Sroberto
12280849Scystatic ctrl_c_fn	ctrl_c_hook;
13280849Scy#ifndef SYS_WINNT
14280849ScyRETSIGTYPE sigint_handler(int);
15280849Scy#else
16280849ScyBOOL WINAPI console_event_handler(DWORD);
17280849Scy#endif
18280849Scy
19280849Scy
2054359Sroberto#ifdef HAVE_SIGACTION
2154359Sroberto
22280849Scy# ifdef SA_RESTART
23280849Scy#  define Z_SA_RESTART		SA_RESTART
24280849Scy# else
25280849Scy#  define Z_SA_RESTART		0
26280849Scy# endif
27280849Scy
2854359Srobertovoid
2954359Srobertosignal_no_reset(
3054359Sroberto	int sig,
31280849Scy	void (*func)(int)
3254359Sroberto	)
3354359Sroberto{
3454359Sroberto	int n;
3554359Sroberto	struct sigaction vec;
36280849Scy	struct sigaction ovec;
3754359Sroberto
38280849Scy	ZERO(vec);
39280849Scy	sigemptyset(&vec.sa_mask);
4054359Sroberto	vec.sa_handler = func;
4154359Sroberto
42280849Scy	/* Added for PPS clocks on Solaris 7 which get EINTR errors */
4356746Sroberto# ifdef SIGPOLL
44280849Scy	if (SIGPOLL == sig)
45280849Scy		vec.sa_flags = Z_SA_RESTART;
4656746Sroberto# endif
4756746Sroberto# ifdef SIGIO
48280849Scy	if (SIGIO == sig)
49280849Scy		vec.sa_flags = Z_SA_RESTART;
5056746Sroberto# endif
5156746Sroberto
52280849Scy	do
5354359Sroberto		n = sigaction(sig, &vec, &ovec);
54280849Scy	while (-1 == n && EINTR == errno);
55280849Scy	if (-1 == n) {
5654359Sroberto		perror("sigaction");
5754359Sroberto		exit(1);
5854359Sroberto	}
5954359Sroberto}
6054359Sroberto
6154359Sroberto#elif  HAVE_SIGVEC
6254359Sroberto
6354359Srobertovoid
6454359Srobertosignal_no_reset(
6554359Sroberto	int sig,
66280849Scy	RETSIGTYPE (*func)(int)
6754359Sroberto	)
6854359Sroberto{
6954359Sroberto	struct sigvec sv;
7054359Sroberto	int n;
7154359Sroberto
72280849Scy	ZERO(sv);
7354359Sroberto	sv.sv_handler = func;
7454359Sroberto	n = sigvec(sig, &sv, (struct sigvec *)NULL);
75280849Scy	if (-1 == n) {
7654359Sroberto		perror("sigvec");
7754359Sroberto		exit(1);
7854359Sroberto	}
7954359Sroberto}
8054359Sroberto
8154359Sroberto#elif  HAVE_SIGSET
8254359Sroberto
8354359Srobertovoid
8454359Srobertosignal_no_reset(
8554359Sroberto	int sig,
86280849Scy	RETSIGTYPE (*func)(int)
8754359Sroberto	)
8854359Sroberto{
8954359Sroberto	int n;
9054359Sroberto
9154359Sroberto	n = sigset(sig, func);
92280849Scy	if (-1 == n) {
9354359Sroberto		perror("sigset");
9454359Sroberto		exit(1);
9554359Sroberto	}
9654359Sroberto}
9754359Sroberto
9854359Sroberto#else
9954359Sroberto
10054359Sroberto/* Beware!	This implementation resets the signal to SIG_DFL */
10154359Srobertovoid
10254359Srobertosignal_no_reset(
10354359Sroberto	int sig,
104280849Scy	RETSIGTYPE (*func)(int)
10554359Sroberto	)
10654359Sroberto{
107280849Scy#ifndef SIG_ERR
108280849Scy# define SIG_ERR	(-1)
109280849Scy#endif
11054359Sroberto	if (SIG_ERR == signal(sig, func)) {
11154359Sroberto		perror("signal");
11254359Sroberto		exit(1);
11354359Sroberto	}
11454359Sroberto}
11554359Sroberto
11654359Sroberto#endif
117280849Scy
118280849Scy#ifndef SYS_WINNT
119280849Scy/*
120280849Scy * POSIX implementation of set_ctrl_c_hook()
121280849Scy */
122280849ScyRETSIGTYPE
123280849Scysigint_handler(
124280849Scy	int	signum
125280849Scy	)
126280849Scy{
127280849Scy	UNUSED_ARG(signum);
128280849Scy	if (ctrl_c_hook != NULL)
129280849Scy		(*ctrl_c_hook)();
130280849Scy}
131280849Scy
132280849Scyvoid
133280849Scyset_ctrl_c_hook(
134280849Scy	ctrl_c_fn	c_hook
135280849Scy	)
136280849Scy{
137280849Scy	RETSIGTYPE (*handler)(int);
138280849Scy
139280849Scy	if (NULL == c_hook) {
140280849Scy		handler = SIG_DFL;
141338530Sdelphij		signal_no_reset(SIGINT, handler);
142338530Sdelphij		ctrl_c_hook = c_hook;
143280849Scy	} else {
144338530Sdelphij		ctrl_c_hook = c_hook;
145280849Scy		handler = &sigint_handler;
146338530Sdelphij		signal_no_reset(SIGINT, handler);
147280849Scy	}
148280849Scy}
149280849Scy#else	/* SYS_WINNT follows */
150280849Scy/*
151280849Scy * Windows implementation of set_ctrl_c_hook()
152280849Scy */
153280849ScyBOOL WINAPI
154280849Scyconsole_event_handler(
155280849Scy	DWORD	dwCtrlType
156280849Scy	)
157280849Scy{
158280849Scy	BOOL handled;
159280849Scy
160280849Scy	if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
161280849Scy		(*ctrl_c_hook)();
162280849Scy		handled = TRUE;
163280849Scy	} else {
164280849Scy		handled = FALSE;
165280849Scy	}
166280849Scy
167280849Scy	return handled;
168280849Scy}
169280849Scyvoid
170280849Scyset_ctrl_c_hook(
171280849Scy	ctrl_c_fn	c_hook
172280849Scy	)
173280849Scy{
174280849Scy	BOOL install;
175280849Scy
176280849Scy	if (NULL == c_hook) {
177280849Scy		ctrl_c_hook = NULL;
178280849Scy		install = FALSE;
179280849Scy	} else {
180280849Scy		ctrl_c_hook = c_hook;
181280849Scy		install = TRUE;
182280849Scy	}
183280849Scy	if (!SetConsoleCtrlHandler(&console_event_handler, install))
184280849Scy		msyslog(LOG_ERR, "Can't %s console control handler: %m",
185280849Scy			(install)
186280849Scy			    ? "add"
187280849Scy			    : "remove");
188280849Scy}
189280849Scy#endif	/* SYS_WINNT */
190