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
12290000Sglebiusstatic ctrl_c_fn	ctrl_c_hook;
13290000Sglebius#ifndef SYS_WINNT
14290000SglebiusRETSIGTYPE sigint_handler(int);
15290000Sglebius#else
16290000SglebiusBOOL WINAPI console_event_handler(DWORD);
17290000Sglebius#endif
18290000Sglebius
19290000Sglebius
2054359Sroberto#ifdef HAVE_SIGACTION
2154359Sroberto
22290000Sglebius# ifdef SA_RESTART
23290000Sglebius#  define Z_SA_RESTART		SA_RESTART
24290000Sglebius# else
25290000Sglebius#  define Z_SA_RESTART		0
26290000Sglebius# endif
27290000Sglebius
2854359Srobertovoid
2954359Srobertosignal_no_reset(
3054359Sroberto	int sig,
31290000Sglebius	void (*func)(int)
3254359Sroberto	)
3354359Sroberto{
3454359Sroberto	int n;
3554359Sroberto	struct sigaction vec;
36290000Sglebius	struct sigaction ovec;
3754359Sroberto
38290000Sglebius	ZERO(vec);
39290000Sglebius	sigemptyset(&vec.sa_mask);
4054359Sroberto	vec.sa_handler = func;
4154359Sroberto
42290000Sglebius	/* Added for PPS clocks on Solaris 7 which get EINTR errors */
4356746Sroberto# ifdef SIGPOLL
44290000Sglebius	if (SIGPOLL == sig)
45290000Sglebius		vec.sa_flags = Z_SA_RESTART;
4656746Sroberto# endif
4756746Sroberto# ifdef SIGIO
48290000Sglebius	if (SIGIO == sig)
49290000Sglebius		vec.sa_flags = Z_SA_RESTART;
5056746Sroberto# endif
5156746Sroberto
52290000Sglebius	do
5354359Sroberto		n = sigaction(sig, &vec, &ovec);
54290000Sglebius	while (-1 == n && EINTR == errno);
55290000Sglebius	if (-1 == n) {
5654359Sroberto		perror("sigaction");
5754359Sroberto		exit(1);
5854359Sroberto	}
5954359Sroberto}
6054359Sroberto
6154359Sroberto#elif  HAVE_SIGVEC
6254359Sroberto
6354359Srobertovoid
6454359Srobertosignal_no_reset(
6554359Sroberto	int sig,
66290000Sglebius	RETSIGTYPE (*func)(int)
6754359Sroberto	)
6854359Sroberto{
6954359Sroberto	struct sigvec sv;
7054359Sroberto	int n;
7154359Sroberto
72290000Sglebius	ZERO(sv);
7354359Sroberto	sv.sv_handler = func;
7454359Sroberto	n = sigvec(sig, &sv, (struct sigvec *)NULL);
75290000Sglebius	if (-1 == n) {
7654359Sroberto		perror("sigvec");
7754359Sroberto		exit(1);
7854359Sroberto	}
7954359Sroberto}
8054359Sroberto
8154359Sroberto#elif  HAVE_SIGSET
8254359Sroberto
8354359Srobertovoid
8454359Srobertosignal_no_reset(
8554359Sroberto	int sig,
86290000Sglebius	RETSIGTYPE (*func)(int)
8754359Sroberto	)
8854359Sroberto{
8954359Sroberto	int n;
9054359Sroberto
9154359Sroberto	n = sigset(sig, func);
92290000Sglebius	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,
104290000Sglebius	RETSIGTYPE (*func)(int)
10554359Sroberto	)
10654359Sroberto{
107290000Sglebius#ifndef SIG_ERR
108290000Sglebius# define SIG_ERR	(-1)
109290000Sglebius#endif
11054359Sroberto	if (SIG_ERR == signal(sig, func)) {
11154359Sroberto		perror("signal");
11254359Sroberto		exit(1);
11354359Sroberto	}
11454359Sroberto}
11554359Sroberto
11654359Sroberto#endif
117290000Sglebius
118290000Sglebius#ifndef SYS_WINNT
119290000Sglebius/*
120290000Sglebius * POSIX implementation of set_ctrl_c_hook()
121290000Sglebius */
122290000SglebiusRETSIGTYPE
123290000Sglebiussigint_handler(
124290000Sglebius	int	signum
125290000Sglebius	)
126290000Sglebius{
127290000Sglebius	UNUSED_ARG(signum);
128290000Sglebius	if (ctrl_c_hook != NULL)
129290000Sglebius		(*ctrl_c_hook)();
130290000Sglebius}
131290000Sglebius
132290000Sglebiusvoid
133290000Sglebiusset_ctrl_c_hook(
134290000Sglebius	ctrl_c_fn	c_hook
135290000Sglebius	)
136290000Sglebius{
137290000Sglebius	RETSIGTYPE (*handler)(int);
138290000Sglebius
139290000Sglebius	if (NULL == c_hook) {
140290000Sglebius		handler = SIG_DFL;
141290000Sglebius		ctrl_c_hook = NULL;
142290000Sglebius	} else {
143290000Sglebius		handler = &sigint_handler;
144290000Sglebius		ctrl_c_hook = c_hook;
145290000Sglebius	}
146290000Sglebius	signal_no_reset(SIGINT, handler);
147290000Sglebius}
148290000Sglebius#else	/* SYS_WINNT follows */
149290000Sglebius/*
150290000Sglebius * Windows implementation of set_ctrl_c_hook()
151290000Sglebius */
152290000SglebiusBOOL WINAPI
153290000Sglebiusconsole_event_handler(
154290000Sglebius	DWORD	dwCtrlType
155290000Sglebius	)
156290000Sglebius{
157290000Sglebius	BOOL handled;
158290000Sglebius
159290000Sglebius	if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
160290000Sglebius		(*ctrl_c_hook)();
161290000Sglebius		handled = TRUE;
162290000Sglebius	} else {
163290000Sglebius		handled = FALSE;
164290000Sglebius	}
165290000Sglebius
166290000Sglebius	return handled;
167290000Sglebius}
168290000Sglebiusvoid
169290000Sglebiusset_ctrl_c_hook(
170290000Sglebius	ctrl_c_fn	c_hook
171290000Sglebius	)
172290000Sglebius{
173290000Sglebius	BOOL install;
174290000Sglebius
175290000Sglebius	if (NULL == c_hook) {
176290000Sglebius		ctrl_c_hook = NULL;
177290000Sglebius		install = FALSE;
178290000Sglebius	} else {
179290000Sglebius		ctrl_c_hook = c_hook;
180290000Sglebius		install = TRUE;
181290000Sglebius	}
182290000Sglebius	if (!SetConsoleCtrlHandler(&console_event_handler, install))
183290000Sglebius		msyslog(LOG_ERR, "Can't %s console control handler: %m",
184290000Sglebius			(install)
185290000Sglebius			    ? "add"
186290000Sglebius			    : "remove");
187290000Sglebius}
188290000Sglebius#endif	/* SYS_WINNT */
189