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