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