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