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
12285612Sdelphijstatic ctrl_c_fn	ctrl_c_hook;
13285612Sdelphij#ifndef SYS_WINNT
14285612SdelphijRETSIGTYPE sigint_handler(int);
15285612Sdelphij#else
16285612SdelphijBOOL WINAPI console_event_handler(DWORD);
17285612Sdelphij#endif
18285612Sdelphij
19285612Sdelphij
2054359Sroberto#ifdef HAVE_SIGACTION
2154359Sroberto
22285612Sdelphij# ifdef SA_RESTART
23285612Sdelphij#  define Z_SA_RESTART		SA_RESTART
24285612Sdelphij# else
25285612Sdelphij#  define Z_SA_RESTART		0
26285612Sdelphij# endif
27285612Sdelphij
2854359Srobertovoid
2954359Srobertosignal_no_reset(
3054359Sroberto	int sig,
31285612Sdelphij	void (*func)(int)
3254359Sroberto	)
3354359Sroberto{
3454359Sroberto	int n;
3554359Sroberto	struct sigaction vec;
36285612Sdelphij	struct sigaction ovec;
3754359Sroberto
38285612Sdelphij	ZERO(vec);
39285612Sdelphij	sigemptyset(&vec.sa_mask);
4054359Sroberto	vec.sa_handler = func;
4154359Sroberto
42285612Sdelphij	/* Added for PPS clocks on Solaris 7 which get EINTR errors */
4356746Sroberto# ifdef SIGPOLL
44285612Sdelphij	if (SIGPOLL == sig)
45285612Sdelphij		vec.sa_flags = Z_SA_RESTART;
4656746Sroberto# endif
4756746Sroberto# ifdef SIGIO
48285612Sdelphij	if (SIGIO == sig)
49285612Sdelphij		vec.sa_flags = Z_SA_RESTART;
5056746Sroberto# endif
5156746Sroberto
52285612Sdelphij	do
5354359Sroberto		n = sigaction(sig, &vec, &ovec);
54285612Sdelphij	while (-1 == n && EINTR == errno);
55285612Sdelphij	if (-1 == n) {
5654359Sroberto		perror("sigaction");
5754359Sroberto		exit(1);
5854359Sroberto	}
5954359Sroberto}
6054359Sroberto
6154359Sroberto#elif  HAVE_SIGVEC
6254359Sroberto
6354359Srobertovoid
6454359Srobertosignal_no_reset(
6554359Sroberto	int sig,
66285612Sdelphij	RETSIGTYPE (*func)(int)
6754359Sroberto	)
6854359Sroberto{
6954359Sroberto	struct sigvec sv;
7054359Sroberto	int n;
7154359Sroberto
72285612Sdelphij	ZERO(sv);
7354359Sroberto	sv.sv_handler = func;
7454359Sroberto	n = sigvec(sig, &sv, (struct sigvec *)NULL);
75285612Sdelphij	if (-1 == n) {
7654359Sroberto		perror("sigvec");
7754359Sroberto		exit(1);
7854359Sroberto	}
7954359Sroberto}
8054359Sroberto
8154359Sroberto#elif  HAVE_SIGSET
8254359Sroberto
8354359Srobertovoid
8454359Srobertosignal_no_reset(
8554359Sroberto	int sig,
86285612Sdelphij	RETSIGTYPE (*func)(int)
8754359Sroberto	)
8854359Sroberto{
8954359Sroberto	int n;
9054359Sroberto
9154359Sroberto	n = sigset(sig, func);
92285612Sdelphij	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,
104285612Sdelphij	RETSIGTYPE (*func)(int)
10554359Sroberto	)
10654359Sroberto{
107285612Sdelphij#ifndef SIG_ERR
108285612Sdelphij# define SIG_ERR	(-1)
109285612Sdelphij#endif
11054359Sroberto	if (SIG_ERR == signal(sig, func)) {
11154359Sroberto		perror("signal");
11254359Sroberto		exit(1);
11354359Sroberto	}
11454359Sroberto}
11554359Sroberto
11654359Sroberto#endif
117285612Sdelphij
118285612Sdelphij#ifndef SYS_WINNT
119285612Sdelphij/*
120285612Sdelphij * POSIX implementation of set_ctrl_c_hook()
121285612Sdelphij */
122285612SdelphijRETSIGTYPE
123285612Sdelphijsigint_handler(
124285612Sdelphij	int	signum
125285612Sdelphij	)
126285612Sdelphij{
127285612Sdelphij	UNUSED_ARG(signum);
128285612Sdelphij	if (ctrl_c_hook != NULL)
129285612Sdelphij		(*ctrl_c_hook)();
130285612Sdelphij}
131285612Sdelphij
132285612Sdelphijvoid
133285612Sdelphijset_ctrl_c_hook(
134285612Sdelphij	ctrl_c_fn	c_hook
135285612Sdelphij	)
136285612Sdelphij{
137285612Sdelphij	RETSIGTYPE (*handler)(int);
138285612Sdelphij
139285612Sdelphij	if (NULL == c_hook) {
140285612Sdelphij		handler = SIG_DFL;
141338531Sdelphij		signal_no_reset(SIGINT, handler);
142338531Sdelphij		ctrl_c_hook = c_hook;
143285612Sdelphij	} else {
144338531Sdelphij		ctrl_c_hook = c_hook;
145285612Sdelphij		handler = &sigint_handler;
146338531Sdelphij		signal_no_reset(SIGINT, handler);
147285612Sdelphij	}
148285612Sdelphij}
149285612Sdelphij#else	/* SYS_WINNT follows */
150285612Sdelphij/*
151285612Sdelphij * Windows implementation of set_ctrl_c_hook()
152285612Sdelphij */
153285612SdelphijBOOL WINAPI
154285612Sdelphijconsole_event_handler(
155285612Sdelphij	DWORD	dwCtrlType
156285612Sdelphij	)
157285612Sdelphij{
158285612Sdelphij	BOOL handled;
159285612Sdelphij
160285612Sdelphij	if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
161285612Sdelphij		(*ctrl_c_hook)();
162285612Sdelphij		handled = TRUE;
163285612Sdelphij	} else {
164285612Sdelphij		handled = FALSE;
165285612Sdelphij	}
166285612Sdelphij
167285612Sdelphij	return handled;
168285612Sdelphij}
169285612Sdelphijvoid
170285612Sdelphijset_ctrl_c_hook(
171285612Sdelphij	ctrl_c_fn	c_hook
172285612Sdelphij	)
173285612Sdelphij{
174285612Sdelphij	BOOL install;
175285612Sdelphij
176285612Sdelphij	if (NULL == c_hook) {
177285612Sdelphij		ctrl_c_hook = NULL;
178285612Sdelphij		install = FALSE;
179285612Sdelphij	} else {
180285612Sdelphij		ctrl_c_hook = c_hook;
181285612Sdelphij		install = TRUE;
182285612Sdelphij	}
183285612Sdelphij	if (!SetConsoleCtrlHandler(&console_event_handler, install))
184285612Sdelphij		msyslog(LOG_ERR, "Can't %s console control handler: %m",
185285612Sdelphij			(install)
186285612Sdelphij			    ? "add"
187285612Sdelphij			    : "remove");
188285612Sdelphij}
189285612Sdelphij#endif	/* SYS_WINNT */
190