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