summaryrefslogtreecommitdiff
path: root/libntp/syssignal.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/syssignal.c')
-rw-r--r--libntp/syssignal.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/libntp/syssignal.c b/libntp/syssignal.c
new file mode 100644
index 0000000..5e496a9
--- /dev/null
+++ b/libntp/syssignal.c
@@ -0,0 +1,188 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#include "ntp_syslog.h"
+#include "ntp_stdlib.h"
+
+static ctrl_c_fn ctrl_c_hook;
+#ifndef SYS_WINNT
+RETSIGTYPE sigint_handler(int);
+#else
+BOOL WINAPI console_event_handler(DWORD);
+#endif
+
+
+#ifdef HAVE_SIGACTION
+
+# ifdef SA_RESTART
+# define Z_SA_RESTART SA_RESTART
+# else
+# define Z_SA_RESTART 0
+# endif
+
+void
+signal_no_reset(
+ int sig,
+ void (*func)(int)
+ )
+{
+ int n;
+ struct sigaction vec;
+ struct sigaction ovec;
+
+ ZERO(vec);
+ sigemptyset(&vec.sa_mask);
+ vec.sa_handler = func;
+
+ /* Added for PPS clocks on Solaris 7 which get EINTR errors */
+# ifdef SIGPOLL
+ if (SIGPOLL == sig)
+ vec.sa_flags = Z_SA_RESTART;
+# endif
+# ifdef SIGIO
+ if (SIGIO == sig)
+ vec.sa_flags = Z_SA_RESTART;
+# endif
+
+ do
+ n = sigaction(sig, &vec, &ovec);
+ while (-1 == n && EINTR == errno);
+ if (-1 == n) {
+ perror("sigaction");
+ exit(1);
+ }
+}
+
+#elif HAVE_SIGVEC
+
+void
+signal_no_reset(
+ int sig,
+ RETSIGTYPE (*func)(int)
+ )
+{
+ struct sigvec sv;
+ int n;
+
+ ZERO(sv);
+ sv.sv_handler = func;
+ n = sigvec(sig, &sv, (struct sigvec *)NULL);
+ if (-1 == n) {
+ perror("sigvec");
+ exit(1);
+ }
+}
+
+#elif HAVE_SIGSET
+
+void
+signal_no_reset(
+ int sig,
+ RETSIGTYPE (*func)(int)
+ )
+{
+ int n;
+
+ n = sigset(sig, func);
+ if (-1 == n) {
+ perror("sigset");
+ exit(1);
+ }
+}
+
+#else
+
+/* Beware! This implementation resets the signal to SIG_DFL */
+void
+signal_no_reset(
+ int sig,
+ RETSIGTYPE (*func)(int)
+ )
+{
+#ifndef SIG_ERR
+# define SIG_ERR (-1)
+#endif
+ if (SIG_ERR == signal(sig, func)) {
+ perror("signal");
+ exit(1);
+ }
+}
+
+#endif
+
+#ifndef SYS_WINNT
+/*
+ * POSIX implementation of set_ctrl_c_hook()
+ */
+RETSIGTYPE
+sigint_handler(
+ int signum
+ )
+{
+ UNUSED_ARG(signum);
+ if (ctrl_c_hook != NULL)
+ (*ctrl_c_hook)();
+}
+
+void
+set_ctrl_c_hook(
+ ctrl_c_fn c_hook
+ )
+{
+ RETSIGTYPE (*handler)(int);
+
+ if (NULL == c_hook) {
+ handler = SIG_DFL;
+ ctrl_c_hook = NULL;
+ } else {
+ handler = &sigint_handler;
+ ctrl_c_hook = c_hook;
+ }
+ signal_no_reset(SIGINT, handler);
+}
+#else /* SYS_WINNT follows */
+/*
+ * Windows implementation of set_ctrl_c_hook()
+ */
+BOOL WINAPI
+console_event_handler(
+ DWORD dwCtrlType
+ )
+{
+ BOOL handled;
+
+ if (CTRL_C_EVENT == dwCtrlType && ctrl_c_hook != NULL) {
+ (*ctrl_c_hook)();
+ handled = TRUE;
+ } else {
+ handled = FALSE;
+ }
+
+ return handled;
+}
+void
+set_ctrl_c_hook(
+ ctrl_c_fn c_hook
+ )
+{
+ BOOL install;
+
+ if (NULL == c_hook) {
+ ctrl_c_hook = NULL;
+ install = FALSE;
+ } else {
+ ctrl_c_hook = c_hook;
+ install = TRUE;
+ }
+ if (!SetConsoleCtrlHandler(&console_event_handler, install))
+ msyslog(LOG_ERR, "Can't %s console control handler: %m",
+ (install)
+ ? "add"
+ : "remove");
+}
+#endif /* SYS_WINNT */