xref: /freebsd/contrib/ntp/libntp/iosignal.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1 /*
2  * iosignal.c - input/output routines for ntpd.	The socket-opening code
3  *		   was shamelessly stolen from ntpd.
4  */
5 
6 /*
7  * [Bug 158]
8  * Do the #includes differently, as under some versions of Linux
9  * sys/param.h has a #undef CONFIG_PHONE line in it.
10  *
11  * As we have ~40 CONFIG_ variables, I don't feel like renaming them
12  * every time somebody adds a new macro to some system header.
13  */
14 
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18 
19 #include <stdio.h>
20 #include <signal.h>
21 #ifdef HAVE_SYS_PARAM_H
22 # include <sys/param.h>
23 #endif /* HAVE_SYS_PARAM_H */
24 #ifdef HAVE_SYS_IOCTL_H
25 # include <sys/ioctl.h>
26 #endif
27 
28 #include <arpa/inet.h>
29 
30 #if _BSDI_VERSION >= 199510
31 # include <ifaddrs.h>
32 #endif
33 
34 # ifdef __QNXNTO__
35 #  include <fcntl.h>
36 #  include <unix.h>
37 #  define FNDELAY O_NDELAY
38 # endif
39 
40 #include "ntp_machine.h"
41 #include "ntpd.h"
42 #include "ntp_io.h"
43 #include "ntp_if.h"
44 #include "ntp_stdlib.h"
45 #include "iosignal.h"
46 
47 #if defined(HAVE_SIGNALED_IO)
48 static RETSIGTYPE sigio_handler	(int);
49 
50 /* consistency safegurad to catch BLOCK/UNBLOCK oversights */
51 static int sigio_block_count = 0;
52 
53 /* main inputhandler to be called on SIGIO */
54 static input_handler_t *input_handler_callback = NULL;
55 
56 # if defined(HAVE_SIGACTION)
57 /*
58  * If sigaction() is used for signal handling and a signal is
59  * pending then the kernel blocks the signal before it calls
60  * the signal handler.
61  *
62  * The variable below is used to take care that the SIGIO signal
63  * is not unintentionally unblocked inside the sigio_handler()
64  * if the handler executes a piece of code that is normally
65  * bracketed by BLOCKIO()/UNBLOCKIO() calls.
66  */
67 static int sigio_handler_active = 0;
68 # endif
69 
70 /*
71  * SIGPOLL and SIGIO ROUTINES.
72  */
73 
74 
75 
76 /*
77  * TTY initialization routines.
78  */
79 int
80 init_clock_sig(
81 	struct refclockio *rio
82 	)
83 {
84 # ifdef USE_TTY_SIGPOLL
85 	{
86 		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
87 		if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0)
88 		{
89 			msyslog(LOG_ERR,
90 				"init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m");
91 			return 1;
92 		}
93 		return 0;
94 	}
95 # else
96 	/*
97 	 * Special cases first!
98 	 */
99 	/* Was: defined(SYS_HPUX) */
100 #  if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT)
101 #define CLOCK_DONE
102 	{
103 		int pgrp, on = 1;
104 
105 		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
106 		pgrp = getpid();
107 		if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1)
108 		{
109 			msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m - EXITING");
110 			exit(1);
111 			/*NOTREACHED*/
112 		}
113 
114 		/*
115 		 * set non-blocking, async I/O on the descriptor
116 		 */
117 		if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1)
118 		{
119 			msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m - EXITING");
120 			exit(1);
121 			/*NOTREACHED*/
122 		}
123 
124 		if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1)
125 		{
126 			msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m - EXITING");
127 			exit(1);
128 			/*NOTREACHED*/
129 		}
130 		return 0;
131 	}
132 #  endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */
133 	/* Was: defined(SYS_AIX) && !defined(_BSD) */
134 #  if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN)
135 	/*
136 	 * SYSV compatibility mode under AIX.
137 	 */
138 #define CLOCK_DONE
139 	{
140 		int pgrp, on = 1;
141 
142 		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
143 		if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1)
144 		{
145 			msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m");
146 			return 1;
147 		}
148 		pgrp = -getpid();
149 		if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1)
150 		{
151 			msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m");
152 			return 1;
153 		}
154 
155 		if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
156 		{
157 			msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
158 			return 1;
159 		}
160 		return 0;
161 	}
162 #  endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */
163 #  ifndef  CLOCK_DONE
164 	{
165 		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
166 #	if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY)
167 		/*
168 		 * there are, however, always exceptions to the rules
169 		 * one is, that OSF accepts SETOWN on TTY fd's only, iff they are
170 		 * CTTYs. SunOS and HPUX do not semm to have this restriction.
171 		 * another question is: how can you do multiple SIGIO from several
172 		 * ttys (as they all should be CTTYs), wondering...
173 		 *
174 		 * kd 95-07-16
175 		 */
176 		if (ioctl(rio->fd, TIOCSCTTY, 0) == -1)
177 		{
178 			msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m");
179 			return 1;
180 		}
181 #	endif /* TIOCSCTTY && USE_FSETOWNCTTY */
182 
183 		if (fcntl(rio->fd, F_SETOWN, getpid()) == -1)
184 		{
185 			msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m");
186 			return 1;
187 		}
188 
189 		if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
190 		{
191 			msyslog(LOG_ERR,
192 				"fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
193 			return 1;
194 		}
195 		return 0;
196 	}
197 #  endif /* CLOCK_DONE */
198 # endif /* !USE_TTY_SIGPOLL  */
199 }
200 
201 
202 
203 void
204 init_socket_sig(
205 	int fd
206 	)
207 {
208 # ifdef USE_UDP_SIGPOLL
209 	{
210 		if (ioctl(fd, I_SETSIG, S_INPUT) < 0)
211 		{
212 			msyslog(LOG_ERR,
213 				"init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m - EXITING");
214 			exit(1);
215 		}
216 	}
217 # else /* USE_UDP_SIGPOLL */
218 	{
219 		int pgrp;
220 # ifdef FIOASYNC
221 		int on = 1;
222 # endif
223 
224 #  if defined(FIOASYNC)
225 		if (ioctl(fd, FIOASYNC, (char *)&on) == -1)
226 		{
227 			msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m - EXITING");
228 			exit(1);
229 			/*NOTREACHED*/
230 		}
231 #  elif defined(FASYNC)
232 		{
233 			int flags;
234 
235 			if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
236 			{
237 				msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m - EXITING");
238 				exit(1);
239 				/*NOTREACHED*/
240 			}
241 			if (fcntl(fd, F_SETFL, flags|FASYNC) < 0)
242 			{
243 				msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m - EXITING");
244 				exit(1);
245 				/*NOTREACHED*/
246 			}
247 		}
248 #  else
249 #	include "Bletch: Need asynchronous I/O!"
250 #  endif
251 
252 #  ifdef UDP_BACKWARDS_SETOWN
253 		pgrp = -getpid();
254 #  else
255 		pgrp = getpid();
256 #  endif
257 
258 #  if defined(SIOCSPGRP)
259 		if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1)
260 		{
261 			msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m - EXITING");
262 			exit(1);
263 			/*NOTREACHED*/
264 		}
265 #  elif defined(FIOSETOWN)
266 		if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1)
267 		{
268 			msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m - EXITING");
269 			exit(1);
270 			/*NOTREACHED*/
271 		}
272 #  elif defined(F_SETOWN)
273 		if (fcntl(fd, F_SETOWN, pgrp) == -1)
274 		{
275 			msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m - EXITING");
276 			exit(1);
277 			/*NOTREACHED*/
278 		}
279 #  else
280 #	include "Bletch: Need to set process(group) to receive SIG(IO|POLL)"
281 #  endif
282 	}
283 # endif /* USE_UDP_SIGPOLL */
284 }
285 
286 static RETSIGTYPE
287 sigio_handler(
288 	int sig
289 	)
290 {
291 	int saved_errno = errno;
292 	l_fp ts;
293 
294 	get_systime(&ts);
295 
296 # if defined(HAVE_SIGACTION)
297 	sigio_handler_active++;
298 	if (sigio_handler_active != 1)  /* This should never happen! */
299 	    msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 1");
300 # endif
301 
302 	INSIST(input_handler_callback != NULL);
303 	(*input_handler_callback)(&ts);
304 
305 # if defined(HAVE_SIGACTION)
306 	sigio_handler_active--;
307 	if (sigio_handler_active != 0)  /* This should never happen! */
308 	    msyslog(LOG_ERR, "sigio_handler: sigio_handler_active != 0");
309 # endif
310 
311 	errno = saved_errno;
312 }
313 
314 /*
315  * Signal support routines.
316  */
317 # ifdef HAVE_SIGACTION
318 void
319 set_signal(input_handler_t *input)
320 {
321 	INSIST(input != NULL);
322 
323 	input_handler_callback = input;
324 
325 	using_sigio = TRUE;
326 #  ifdef USE_SIGIO
327 	(void) signal_no_reset(SIGIO, sigio_handler);
328 # endif
329 #  ifdef USE_SIGPOLL
330 	(void) signal_no_reset(SIGPOLL, sigio_handler);
331 # endif
332 }
333 
334 void
335 block_io_and_alarm(void)
336 {
337 	sigset_t set;
338 
339 	if (sigemptyset(&set))
340 	    msyslog(LOG_ERR, "block_io_and_alarm: sigemptyset() failed: %m");
341 #  if defined(USE_SIGIO)
342 	if (sigaddset(&set, SIGIO))
343 	    msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGIO) failed: %m");
344 #  endif
345 #  if defined(USE_SIGPOLL)
346 	if (sigaddset(&set, SIGPOLL))
347 	    msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
348 #  endif
349 	if (sigaddset(&set, SIGALRM))
350 	    msyslog(LOG_ERR, "block_io_and_alarm: sigaddset(SIGALRM) failed: %m");
351 
352 	if (sigprocmask(SIG_BLOCK, &set, NULL))
353 	    msyslog(LOG_ERR, "block_io_and_alarm: sigprocmask() failed: %m");
354 }
355 
356 void
357 block_sigio(void)
358 {
359 	if ( sigio_handler_active == 0 )  /* not called from within signal handler */
360 	{
361 		sigset_t set;
362 
363 		++sigio_block_count;
364 		if (sigio_block_count > 1)
365 		    msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
366 		if (sigio_block_count < 1)
367 		    msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
368 
369 		if (sigemptyset(&set))
370 		    msyslog(LOG_ERR, "block_sigio: sigemptyset() failed: %m");
371 #	if defined(USE_SIGIO)
372 		if (sigaddset(&set, SIGIO))
373 		    msyslog(LOG_ERR, "block_sigio: sigaddset(SIGIO) failed: %m");
374 #	endif
375 #	if defined(USE_SIGPOLL)
376 		if (sigaddset(&set, SIGPOLL))
377 		    msyslog(LOG_ERR, "block_sigio: sigaddset(SIGPOLL) failed: %m");
378 #	endif
379 
380 		if (sigprocmask(SIG_BLOCK, &set, NULL))
381 		    msyslog(LOG_ERR, "block_sigio: sigprocmask() failed: %m");
382 	}
383 }
384 
385 void
386 unblock_io_and_alarm(void)
387 {
388 	sigset_t unset;
389 
390 	if (sigemptyset(&unset))
391 	    msyslog(LOG_ERR, "unblock_io_and_alarm: sigemptyset() failed: %m");
392 
393 #  if defined(USE_SIGIO)
394 	if (sigaddset(&unset, SIGIO))
395 	    msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGIO) failed: %m");
396 #  endif
397 #  if defined(USE_SIGPOLL)
398 	if (sigaddset(&unset, SIGPOLL))
399 	    msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGPOLL) failed: %m");
400 #  endif
401 	if (sigaddset(&unset, SIGALRM))
402 	    msyslog(LOG_ERR, "unblock_io_and_alarm: sigaddset(SIGALRM) failed: %m");
403 
404 	if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
405 	    msyslog(LOG_ERR, "unblock_io_and_alarm: sigprocmask() failed: %m");
406 }
407 
408 void
409 unblock_sigio(void)
410 {
411 	if ( sigio_handler_active == 0 )  /* not called from within signal handler */
412 	{
413 		sigset_t unset;
414 
415 		--sigio_block_count;
416 		if (sigio_block_count > 0)
417 		    msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
418 		if (sigio_block_count < 0)
419 		    msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
420 
421 		if (sigemptyset(&unset))
422 		    msyslog(LOG_ERR, "unblock_sigio: sigemptyset() failed: %m");
423 
424 #	if defined(USE_SIGIO)
425 		if (sigaddset(&unset, SIGIO))
426 		    msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGIO) failed: %m");
427 #	endif
428 #	if defined(USE_SIGPOLL)
429 		if (sigaddset(&unset, SIGPOLL))
430 		    msyslog(LOG_ERR, "unblock_sigio: sigaddset(SIGPOLL) failed: %m");
431 #	endif
432 
433 		if (sigprocmask(SIG_UNBLOCK, &unset, NULL))
434 		    msyslog(LOG_ERR, "unblock_sigio: sigprocmask() failed: %m");
435 	}
436 }
437 
438 void
439 wait_for_signal(void)
440 {
441 	sigset_t old;
442 
443 	if (sigprocmask(SIG_UNBLOCK, NULL, &old))
444 	    msyslog(LOG_ERR, "wait_for_signal: sigprocmask() failed: %m");
445 
446 #  if defined(USE_SIGIO)
447 	if (sigdelset(&old, SIGIO))
448 	    msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGIO) failed: %m");
449 #  endif
450 #  if defined(USE_SIGPOLL)
451 	if (sigdelset(&old, SIGPOLL))
452 	    msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGPOLL) failed: %m");
453 #  endif
454 	if (sigdelset(&old, SIGALRM))
455 	    msyslog(LOG_ERR, "wait_for_signal: sigdelset(SIGALRM) failed: %m");
456 
457 	if (sigsuspend(&old) && (errno != EINTR))
458 	    msyslog(LOG_ERR, "wait_for_signal: sigsuspend() failed: %m");
459 }
460 
461 # else /* !HAVE_SIGACTION */
462 /*
463  * Must be an old bsd system.
464  * We assume there is no SIGPOLL.
465  */
466 
467 void
468 block_io_and_alarm(void)
469 {
470 	int mask;
471 
472 	mask = sigmask(SIGIO) | sigmask(SIGALRM);
473 	if (sigblock(mask))
474 	    msyslog(LOG_ERR, "block_io_and_alarm: sigblock() failed: %m");
475 }
476 
477 void
478 block_sigio(void)
479 {
480 	int mask;
481 
482 	++sigio_block_count;
483 	if (sigio_block_count > 1)
484 	    msyslog(LOG_INFO, "block_sigio: sigio_block_count > 1");
485 	if (sigio_block_count < 1)
486 	    msyslog(LOG_INFO, "block_sigio: sigio_block_count < 1");
487 
488 	mask = sigmask(SIGIO);
489 	if (sigblock(mask))
490 	    msyslog(LOG_ERR, "block_sigio: sigblock() failed: %m");
491 }
492 
493 void
494 set_signal(input_handler_t *input)
495 {
496 	INSIST(input != NULL);
497 
498 	input_handler_callback = input;
499 
500 	using_sigio = TRUE;
501 	(void) signal_no_reset(SIGIO, sigio_handler);
502 }
503 
504 void
505 unblock_io_and_alarm(void)
506 {
507 	int mask, omask;
508 
509 	mask = sigmask(SIGIO) | sigmask(SIGALRM);
510 	omask = sigblock(0);
511 	omask &= ~mask;
512 	(void) sigsetmask(omask);
513 }
514 
515 void
516 unblock_sigio(void)
517 {
518 	int mask, omask;
519 
520 	--sigio_block_count;
521 	if (sigio_block_count > 0)
522 	    msyslog(LOG_INFO, "unblock_sigio: sigio_block_count > 0");
523 	if (sigio_block_count < 0)
524 	    msyslog(LOG_INFO, "unblock_sigio: sigio_block_count < 0");
525 	mask = sigmask(SIGIO);
526 	omask = sigblock(0);
527 	omask &= ~mask;
528 	(void) sigsetmask(omask);
529 }
530 
531 void
532 wait_for_signal(void)
533 {
534 	int mask, omask;
535 
536 	mask = sigmask(SIGIO) | sigmask(SIGALRM);
537 	omask = sigblock(0);
538 	omask &= ~mask;
539 	if (sigpause(omask) && (errno != EINTR))
540 	    msyslog(LOG_ERR, "wait_for_signal: sigspause() failed: %m");
541 }
542 
543 # endif /* HAVE_SIGACTION */
544 #else
545 int  NotAnEmptyCompilationUnit;
546 #endif
547