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