diff options
Diffstat (limited to 'libntp/iosignal.c')
-rw-r--r-- | libntp/iosignal.c | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/libntp/iosignal.c b/libntp/iosignal.c new file mode 100644 index 0000000..bcad890 --- /dev/null +++ b/libntp/iosignal.c @@ -0,0 +1,544 @@ +/* + * iosignal.c - input/output routines for ntpd. The socket-opening code + * was shamelessly stolen from ntpd. + */ + +#include "ntp_machine.h" +#include "ntpd.h" +#include "ntp_io.h" +#include "ntp_if.h" +#include "ntp_stdlib.h" +#include "iosignal.h" + +#include <stdio.h> +#include <signal.h> +#ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif /* HAVE_SYS_PARAM_H */ +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +#include <arpa/inet.h> + +#if _BSDI_VERSION >= 199510 +# include <ifaddrs.h> +#endif + +#if defined(HAVE_SIGNALED_IO) +static int sigio_block_count = 0; +# if defined(HAVE_SIGACTION) +/* + * If sigaction() is used for signal handling and a signal is + * pending then the kernel blocks the signal before it calls + * the signal handler. + * + * The variable below is used to take care that the SIGIO signal + * is not unintentionally unblocked inside the sigio_handler() + * if the handler executes a piece of code that is normally + * bracketed by BLOCKIO()/UNBLOCKIO() calls. + */ +static int sigio_handler_active = 0; +# endif +extern void input_handler P((l_fp *)); + +/* + * SIGPOLL and SIGIO ROUTINES. + */ + + /* + * Some systems (MOST) define SIGPOLL == SIGIO, others SIGIO == SIGPOLL, and + * a few have separate SIGIO and SIGPOLL signals. This code checks for the + * SIGIO == SIGPOLL case at compile time. + * Do not define USE_SIGPOLL or USE_SIGIO. + * these are interal only to iosignal.c! + */ +# if defined(USE_SIGPOLL) +# undef USE_SIGPOLL +# endif +# if defined(USE_SIGIO) +# undef USE_SIGIO +# endif + +# if defined(USE_TTY_SIGPOLL) || defined(USE_UDP_SIGPOLL) +# define USE_SIGPOLL +# endif + +# if !defined(USE_TTY_SIGPOLL) || !defined(USE_UDP_SIGPOLL) +# define USE_SIGIO +# endif + +# ifdef __QNXNTO__ +# include <fcntl.h> +# include <unix.h> +# define FNDELAY O_NDELAY +# endif + +# if defined(USE_SIGIO) && defined(USE_SIGPOLL) +# if SIGIO == SIGPOLL +# define USE_SIGIO +# undef USE_SIGPOLL +# endif /* SIGIO == SIGPOLL */ +# endif /* USE_SIGIO && USE_SIGIO */ + + +/* + * TTY initialization routines. + */ +int +init_clock_sig( + struct refclockio *rio + ) +{ +# ifdef USE_TTY_SIGPOLL + { + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0) + { + msyslog(LOG_ERR, + "init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); + return 1; + } + return 0; + } +# else + /* + * Special cases first! + */ + /* Was: defined(SYS_HPUX) */ +# if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT) +#define CLOCK_DONE + { + int pgrp, on = 1; + + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + pgrp = getpid(); + if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + + /* + * set non-blocking, async I/O on the descriptor + */ + if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + + if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m"); + exit(1); + /*NOTREACHED*/ + } + return 0; + } +# endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */ + /* Was: defined(SYS_AIX) && !defined(_BSD) */ +# if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN) + /* + * SYSV compatibility mode under AIX. + */ +#define CLOCK_DONE + { + int pgrp, on = 1; + + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ + if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m"); + return 1; + } + pgrp = -getpid(); + if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) + { + msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; + } +# endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */ +# ifndef CLOCK_DONE + { + /* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */ +# if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY) + /* + * there are, however, always exceptions to the rules + * one is, that OSF accepts SETOWN on TTY fd's only, iff they are + * CTTYs. SunOS and HPUX do not semm to have this restriction. + * another question is: how can you do multiple SIGIO from several + * ttys (as they all should be CTTYs), wondering... + * + * kd 95-07-16 + */ + if (ioctl(rio->fd, TIOCSCTTY, 0) == -1) + { + msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m"); + return 1; + } +# endif /* TIOCSCTTY && USE_FSETOWNCTTY */ + + if (fcntl(rio->fd, F_SETOWN, getpid()) == -1) + { + msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m"); + return 1; + } + + if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0) + { + msyslog(LOG_ERR, + "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m"); + return 1; + } + return 0; + } +# endif /* CLOCK_DONE */ +# endif /* !USE_TTY_SIGPOLL */ +} + + + +void +init_socket_sig( + int fd + ) +{ +# ifdef USE_UDP_SIGPOLL + { + if (ioctl(fd, I_SETSIG, S_INPUT) < 0) + { + msyslog(LOG_ERR, + "init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m"); + exit(1); + } + } +# else /* USE_UDP_SIGPOLL */ + { + int pgrp; +# ifdef FIOASYNC + int on = 1; +# endif + +# if defined(FIOASYNC) + if (ioctl(fd, FIOASYNC, (char *)&on) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(FASYNC) + { + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + { + msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + if (fcntl(fd, F_SETFL, flags|FASYNC) < 0) + { + msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m"); + exit(1); + /*NOTREACHED*/ + } + } +# else +# include "Bletch: Need asynchronous I/O!" +# endif + +# ifdef UDP_BACKWARDS_SETOWN + pgrp = -getpid(); +# else + pgrp = getpid(); +# endif + +# if defined(SIOCSPGRP) + if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(FIOSETOWN) + if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1) + { + msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# elif defined(F_SETOWN) + if (fcntl(fd, F_SETOWN, pgrp) == -1) + { + msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m"); + exit(1); + /*NOTREACHED*/ + } +# else +# include "Bletch: Need to set process(group) to receive SIG(IO|POLL)" +# endif + } +# endif /* USE_UDP_SIGPOLL */ +} + +RETSIGTYPE +sigio_handler( + int sig + ) +{ + int saved_errno = errno; + l_fp ts; + + get_systime(&ts); + +# if defined(HAVE_SIGACTION) + sigio_handler_active++; + if (sigio_handler_active != 1) /* This should never happen! */ + msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 1"); +# endif + + (void)input_handler(&ts); + +# if defined(HAVE_SIGACTION) + sigio_handler_active--; + if (sigio_handler_active != 0) /* This should never happen! */ + msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 0"); +# endif + + errno = saved_errno; +} + +/* + * Signal support routines. + */ +# ifdef HAVE_SIGACTION +void +set_signal(void) +{ +# ifdef USE_SIGIO + (void) signal_no_reset(SIGIO, sigio_handler); +# endif +# ifdef USE_SIGPOLL + (void) signal_no_reset(SIGPOLL, sigio_handler); +# endif +} + +void +block_io_and_alarm(void) +{ + sigset_t set; + + if (sigemptyset(&set)) + msyslog(LOG_ERR, "block_io_and_alarm: sigemptyset() failed: %m"); +# if defined(USE_SIGIO) + if (sigaddset(&set, SIGIO)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&set, SIGPOLL)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGPOLL) failed: %m"); +# endif + if (sigaddset(&set, SIGALRM)) + msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGALRM) failed: %m"); + + if (sigprocmask(SIG_BLOCK, &set, NULL)) + msyslog(LOG_ERR, "block_io_and_alarm: sigprocmask() failed: %m"); +} + +void +block_sigio(void) +{ + if ( sigio_handler_active == 0 ) /* not called from within signal handler */ + { + sigset_t set; + + ++sigio_block_count; + if (sigio_block_count > 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1"); + if (sigio_block_count < 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1"); + + if (sigemptyset(&set)) + msyslog(LOG_ERR, "block_sigio: sigemptyset() failed: %m"); +# if defined(USE_SIGIO) + if (sigaddset(&set, SIGIO)) + msyslog(LOG_ERR, "block_sigio: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&set, SIGPOLL)) + msyslog(LOG_ERR, "block_sigio: sigaddset(SIGPOLL) failed: %m"); +# endif + + if (sigprocmask(SIG_BLOCK, &set, NULL)) + msyslog(LOG_ERR, "block_sigio: sigprocmask() failed: %m"); + } +} + +void +unblock_io_and_alarm(void) +{ + sigset_t unset; + + if (sigemptyset(&unset)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigemptyset() failed: %m"); + +# if defined(USE_SIGIO) + if (sigaddset(&unset, SIGIO)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&unset, SIGPOLL)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGPOLL) failed: %m"); +# endif + if (sigaddset(&unset, SIGALRM)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGALRM) failed: %m"); + + if (sigprocmask(SIG_UNBLOCK, &unset, NULL)) + msyslog(LOG_ERR, "unblock_io_and_alarm: sigprocmask() failed: %m"); +} + +void +unblock_sigio(void) +{ + if ( sigio_handler_active == 0 ) /* not called from within signal handler */ + { + sigset_t unset; + + --sigio_block_count; + if (sigio_block_count > 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0"); + if (sigio_block_count < 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0"); + + if (sigemptyset(&unset)) + msyslog(LOG_ERR, "unblock_sigio: sigemptyset() failed: %m"); + +# if defined(USE_SIGIO) + if (sigaddset(&unset, SIGIO)) + msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigaddset(&unset, SIGPOLL)) + msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGPOLL) failed: %m"); +# endif + + if (sigprocmask(SIG_UNBLOCK, &unset, NULL)) + msyslog(LOG_ERR, "unblock_sigio: sigprocmask() failed: %m"); + } +} + +void +wait_for_signal(void) +{ + sigset_t old; + + if (sigprocmask(SIG_UNBLOCK, NULL, &old)) + msyslog(LOG_ERR, "wait_for_signal: sigprocmask() failed: %m"); + +# if defined(USE_SIGIO) + if (sigdelset(&old, SIGIO)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGIO) failed: %m"); +# endif +# if defined(USE_SIGPOLL) + if (sigdelset(&old, SIGPOLL)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGPOLL) failed: %m"); +# endif + if (sigdelset(&old, SIGALRM)) + msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGALRM) failed: %m"); + + if (sigsuspend(&old) && (errno != EINTR)) + msyslog(LOG_ERR, "wait_for_signal: sigsuspend() failed: %m"); +} + +# else /* !HAVE_SIGACTION */ +/* + * Must be an old bsd system. + * We assume there is no SIGPOLL. + */ + +void +block_io_and_alarm(void) +{ + int mask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + if (sigblock(mask)) + msyslog(LOG_ERR, "block_io_and_alarm: sigblock() failed: %m"); +} + +void +block_sigio(void) +{ + int mask; + + ++sigio_block_count; + if (sigio_block_count > 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1"); + if (sigio_block_count < 1) + msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1"); + + mask = sigmask(SIGIO); + if (sigblock(mask)) + msyslog(LOG_ERR, "block_sigio: sigblock() failed: %m"); +} + +void +set_signal(void) +{ + (void) signal_no_reset(SIGIO, sigio_handler); +} + +void +unblock_io_and_alarm(void) +{ + int mask, omask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + (void) sigsetmask(omask); +} + +void +unblock_sigio(void) +{ + int mask, omask; + + --sigio_block_count; + if (sigio_block_count > 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0"); + if (sigio_block_count < 0) + msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0"); + mask = sigmask(SIGIO); + omask = sigblock(0); + omask &= ~mask; + (void) sigsetmask(omask); +} + +void +wait_for_signal(void) +{ + int mask, omask; + + mask = sigmask(SIGIO) | sigmask(SIGALRM); + omask = sigblock(0); + omask &= ~mask; + if (sigpause(omask) && (errno != EINTR)) + msyslog(LOG_ERR, "wait_for_signal: sigspause() failed: %m"); +} + +# endif /* HAVE_SIGACTION */ +#else +int NotAnEmptyCompilationUnit; +#endif |