Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / ntpd / ntpd.c
1 /*
2  * ntpd.c - main program for the fixed point NTP daemon
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include "ntpd.h"
10 #include "ntp_io.h"
11 #include "ntp_stdlib.h"
12
13 #ifdef HAVE_UNISTD_H
14 # include <unistd.h>
15 #endif
16 #ifdef HAVE_SYS_STAT_H
17 # include <sys/stat.h>
18 #endif
19 #include <stdio.h>
20 #ifndef SYS_WINNT
21 # if !defined(VMS)      /*wjm*/
22 #  include <sys/param.h>
23 # endif /* VMS */
24 # include <sys/signal.h>
25 # ifdef HAVE_SYS_IOCTL_H
26 #  include <sys/ioctl.h>
27 # endif /* HAVE_SYS_IOCTL_H */
28 # ifdef HAVE_SYS_RESOURCE_H
29 #  include <sys/resource.h>
30 # endif /* HAVE_SYS_RESOURCE_H */
31 #else
32 # include <signal.h>
33 # include <process.h>
34 # include <io.h>
35 # include "../libntp/log.h"
36 # include <crtdbg.h>
37 #endif /* SYS_WINNT */
38 #if defined(HAVE_RTPRIO)
39 # ifdef HAVE_SYS_RESOURCE_H
40 #  include <sys/resource.h>
41 # endif
42 # ifdef HAVE_SYS_LOCK_H
43 #  include <sys/lock.h>
44 # endif
45 # include <sys/rtprio.h>
46 #else
47 # ifdef HAVE_PLOCK
48 #  ifdef HAVE_SYS_LOCK_H
49 #       include <sys/lock.h>
50 #  endif
51 # endif
52 #endif
53 #if defined(HAVE_SCHED_SETSCHEDULER)
54 # ifdef HAVE_SCHED_H
55 #  include <sched.h>
56 # else
57 #  ifdef HAVE_SYS_SCHED_H
58 #   include <sys/sched.h>
59 #  endif
60 # endif
61 #endif
62 #if defined(HAVE_SYS_MMAN_H)
63 # include <sys/mman.h>
64 #endif
65
66 #ifdef HAVE_TERMIOS_H
67 # include <termios.h>
68 #endif
69
70 #ifdef SYS_DOMAINOS
71 # include <apollo/base.h>
72 #endif /* SYS_DOMAINOS */
73
74 #include "recvbuff.h"  
75 #include "ntp_cmdargs.h"  
76
77 #if 0                           /* HMS: I don't think we need this. 961223 */
78 #ifdef LOCK_PROCESS
79 # ifdef SYS_SOLARIS
80 #  include <sys/mman.h>
81 # else
82 #  include <sys/lock.h>
83 # endif
84 #endif
85 #endif
86
87 #ifdef _AIX
88 # include <ulimit.h>
89 #endif /* _AIX */
90
91 #ifdef SCO5_CLOCK
92 # include <sys/ci/ciioctl.h>
93 #endif
94
95 #ifdef PUBKEY
96 #include "ntp_crypto.h"
97 #endif /* PUBKEY */
98
99 /*
100  * Signals we catch for debugging.      If not debugging we ignore them.
101  */
102 #define MOREDEBUGSIG    SIGUSR1
103 #define LESSDEBUGSIG    SIGUSR2
104
105 /*
106  * Signals which terminate us gracefully.
107  */
108 #ifndef SYS_WINNT
109 # define SIGDIE1        SIGHUP
110 # define SIGDIE3        SIGQUIT
111 # define SIGDIE2        SIGINT
112 # define SIGDIE4        SIGTERM
113 #endif /* SYS_WINNT */
114
115 #if defined SYS_WINNT
116 /* handles for various threads, process, and objects */
117 HANDLE ResolverThreadHandle = NULL;
118 /* variables used to inform the Service Control Manager of our current state */
119 SERVICE_STATUS ssStatus;
120 SERVICE_STATUS_HANDLE   sshStatusHandle;
121 HANDLE WaitHandles[2] = { NULL, NULL };
122 char szMsgPath[255];
123 static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType);
124 #endif /* SYS_WINNT */
125
126 /*
127  * Scheduling priority we run at
128  */
129 #define NTPD_PRIO       (-12)
130
131 int priority_done = 2;          /* 0 - Set priority */
132                                 /* 1 - priority is OK where it is */
133                                 /* 2 - Don't set priority */
134                                 /* 1 and 2 are pretty much the same */
135
136 /*
137  * Debugging flag
138  */
139 volatile int debug;
140
141 /*
142  * No-fork flag.  If set, we do not become a background daemon.
143  */
144 int nofork;
145
146 /*
147  * Initializing flag.  All async routines watch this and only do their
148  * thing when it is clear.
149  */
150 int initializing;
151
152 /*
153  * Version declaration
154  */
155 extern const char *Version;
156
157 int was_alarmed;
158
159 #ifdef DECL_SYSCALL
160 /*
161  * We put this here, since the argument profile is syscall-specific
162  */
163 extern int syscall      P((int, ...));
164 #endif /* DECL_SYSCALL */
165
166
167 #ifdef  SIGDIE2
168 static  RETSIGTYPE      finish          P((int));
169 #endif  /* SIGDIE2 */
170
171 #ifdef  DEBUG
172 static  RETSIGTYPE      moredebug       P((int));
173 static  RETSIGTYPE      lessdebug       P((int));
174 #else /* not DEBUG */
175 static  RETSIGTYPE      no_debug        P((int));
176 #endif  /* not DEBUG */
177
178 int             ntpdmain                P((int, char **));
179 static void     set_process_priority    P((void));
180
181
182 #ifdef NO_MAIN_ALLOWED
183 CALL(ntpd,"ntpd",ntpdmain);
184 #else
185 int
186 main(
187         int argc,
188         char *argv[]
189         )
190 {
191         return ntpdmain(argc, argv);
192 }
193 #endif
194
195 #ifdef _AIX
196 /*
197  * OK. AIX is different than solaris in how it implements plock().
198  * If you do NOT adjust the stack limit, you will get the MAXIMUM
199  * stack size allocated and PINNED with you program. To check the 
200  * value, use ulimit -a. 
201  *
202  * To fix this, we create an automatic variable and set our stack limit 
203  * to that PLUS 32KB of extra space (we need some headroom).
204  *
205  * This subroutine gets the stack address.
206  *
207  * Grover Davidson and Matt Ladendorf
208  *
209  */
210 static char *
211 get_aix_stack(void)
212 {
213         char ch;
214         return (&ch);
215 }
216
217 /*
218  * Signal handler for SIGDANGER.
219  */
220 static void
221 catch_danger(int signo)
222 {
223         msyslog(LOG_INFO, "ntpd: setpgid(): %m");
224         /* Make the system believe we'll free something, but don't do it! */
225         return;
226 }
227 #endif /* _AIX */
228
229 /*
230  * Set the process priority
231  */
232 static void
233 set_process_priority(void)
234 {
235
236 #ifdef DEBUG
237         if (debug > 1)
238                 msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>",
239                         ((priority_done)
240                          ? "Leave priority alone"
241                          : "Attempt to set priority"
242                                 ),
243                         priority_done);
244 #endif /* DEBUG */
245
246 #ifdef SYS_WINNT
247         priority_done += NT_set_process_priority();
248 #endif
249
250 #if defined(HAVE_SCHED_SETSCHEDULER)
251         if (!priority_done) {
252                 extern int config_priority_override, config_priority;
253                 int pmax, pmin;
254                 struct sched_param sched;
255
256                 pmax = sched_get_priority_max(SCHED_FIFO);
257                 sched.sched_priority = pmax;
258                 if ( config_priority_override ) {
259                         pmin = sched_get_priority_min(SCHED_FIFO);
260                         if ( config_priority > pmax )
261                                 sched.sched_priority = pmax;
262                         else if ( config_priority < pmin )
263                                 sched.sched_priority = pmin;
264                         else
265                                 sched.sched_priority = config_priority;
266                 }
267                 if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 )
268                         msyslog(LOG_ERR, "sched_setscheduler(): %m");
269                 else
270                         ++priority_done;
271         }
272 #endif /* HAVE_SCHED_SETSCHEDULER */
273 #if defined(HAVE_RTPRIO)
274 # ifdef RTP_SET
275         if (!priority_done) {
276                 struct rtprio srtp;
277
278                 srtp.type = RTP_PRIO_REALTIME;  /* was: RTP_PRIO_NORMAL */
279                 srtp.prio = 0;          /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */
280
281                 if (rtprio(RTP_SET, getpid(), &srtp) < 0)
282                         msyslog(LOG_ERR, "rtprio() error: %m");
283                 else
284                         ++priority_done;
285         }
286 # else /* not RTP_SET */
287         if (!priority_done) {
288                 if (rtprio(0, 120) < 0)
289                         msyslog(LOG_ERR, "rtprio() error: %m");
290                 else
291                         ++priority_done;
292         }
293 # endif /* not RTP_SET */
294 #endif  /* HAVE_RTPRIO */
295 #if defined(NTPD_PRIO) && NTPD_PRIO != 0
296 # ifdef HAVE_ATT_NICE
297         if (!priority_done) {
298                 errno = 0;
299                 if (-1 == nice (NTPD_PRIO) && errno != 0)
300                         msyslog(LOG_ERR, "nice() error: %m");
301                 else
302                         ++priority_done;
303         }
304 # endif /* HAVE_ATT_NICE */
305 # ifdef HAVE_BSD_NICE
306         if (!priority_done) {
307                 if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO))
308                         msyslog(LOG_ERR, "setpriority() error: %m");
309                 else
310                         ++priority_done;
311         }
312 # endif /* HAVE_BSD_NICE */
313 #endif /* NTPD_PRIO && NTPD_PRIO != 0 */
314         if (!priority_done)
315                 msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority");
316 }
317
318
319 /*
320  * Main program.  Initialize us, disconnect us from the tty if necessary,
321  * and loop waiting for I/O and/or timer expiries.
322  */
323 int
324 ntpdmain(
325         int argc,
326         char *argv[]
327         )
328 {
329         l_fp now;
330         char *cp;
331 #ifdef AUTOKEY
332         u_int n;
333         char hostname[MAXFILENAME];
334 #endif /* AUTOKEY */
335         struct recvbuf *rbuflist;
336         struct recvbuf *rbuf;
337 #ifdef _AIX                     /* HMS: ifdef SIGDANGER? */
338         struct sigaction sa;
339 #endif
340
341         initializing = 1;               /* mark that we are initializing */
342         debug = 0;                      /* no debugging by default */
343         nofork = 0;                     /* will fork by default */
344
345 #ifdef HAVE_UMASK
346         {
347                 mode_t uv;
348
349                 uv = umask(0);
350                 if(uv)
351                         (void) umask(uv);
352                 else
353                         (void) umask(022);
354         }
355 #endif
356
357 #ifdef HAVE_GETUID
358         {
359                 uid_t uid;
360
361                 uid = getuid();
362                 if (uid)
363                 {
364                         msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid);
365                         exit(1);
366                 }
367         }
368 #endif
369
370 #ifdef SYS_WINNT
371         /* Set the Event-ID message-file name. */
372         if (!GetModuleFileName(NULL, szMsgPath, sizeof(szMsgPath))) {
373                 msyslog(LOG_ERR, "GetModuleFileName(PGM_EXE_FILE) failed: %m\n");
374                 exit(1);
375         }
376         addSourceToRegistry("NTP", szMsgPath);
377 #endif
378         getstartup(argc, argv); /* startup configuration, may set debug */
379
380         /*
381          * Initialize random generator and public key pair
382          */
383         get_systime(&now);
384         SRANDOM((int)(now.l_i * now.l_uf));
385
386 #if !defined(VMS)
387 # ifndef NODETACH
388         /*
389          * Detach us from the terminal.  May need an #ifndef GIZMO.
390          */
391 #  ifdef DEBUG
392         if (!debug && !nofork)
393 #  else /* DEBUG */
394         if (!nofork)
395 #  endif /* DEBUG */
396         {
397 #  ifndef SYS_WINNT
398 #   ifdef HAVE_DAEMON
399                 daemon(0, 0);
400 #   else /* not HAVE_DAEMON */
401                 if (fork())     /* HMS: What about a -1? */
402                         exit(0);
403
404                 {
405 #if !defined(F_CLOSEM)
406                         u_long s;
407                         int max_fd;
408 #endif /* not F_CLOSEM */
409
410                         /*
411                          * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
412                          * by Eric Agar (saves us from doing 32767 system
413                          * calls)
414                          */
415 #if defined(F_CLOSEM)
416                         if (fcntl(0, F_CLOSEM, 0) == -1)
417                             msyslog(LOG_ERR, "ntpd: failed to close open files(): %m");
418 #else  /* not F_CLOSEM */
419
420 # if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
421                         max_fd = sysconf(_SC_OPEN_MAX);
422 # else /* HAVE_SYSCONF && _SC_OPEN_MAX */
423                         max_fd = getdtablesize();
424 # endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
425                         for (s = 0; s < max_fd; s++)
426                                 (void) close((int)s);
427 #endif /* not F_CLOSEM */
428                         (void) open("/", 0);
429                         (void) dup2(0, 1);
430                         (void) dup2(0, 2);
431 #ifdef SYS_DOMAINOS
432                         {
433                                 uid_$t puid;
434                                 status_$t st;
435
436                                 proc2_$who_am_i(&puid);
437                                 proc2_$make_server(&puid, &st);
438                         }
439 #endif /* SYS_DOMAINOS */
440 #if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
441 # ifdef HAVE_SETSID
442                         if (setsid() == (pid_t)-1)
443                                 msyslog(LOG_ERR, "ntpd: setsid(): %m");
444 # else
445                         if (setpgid(0, 0) == -1)
446                                 msyslog(LOG_ERR, "ntpd: setpgid(): %m");
447 # endif
448 #else /* HAVE_SETPGID || HAVE_SETSID */
449                         {
450 # if defined(TIOCNOTTY)
451                                 int fid;
452
453                                 fid = open("/dev/tty", 2);
454                                 if (fid >= 0)
455                                 {
456                                         (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
457                                         (void) close(fid);
458                                 }
459 # endif /* defined(TIOCNOTTY) */
460 # ifdef HAVE_SETPGRP_0
461                                 (void) setpgrp();
462 # else /* HAVE_SETPGRP_0 */
463                                 (void) setpgrp(0, getpid());
464 # endif /* HAVE_SETPGRP_0 */
465                         }
466 #endif /* HAVE_SETPGID || HAVE_SETSID */
467 #ifdef _AIX
468                         /* Don't get killed by low-on-memory signal. */
469                         sa.sa_handler = catch_danger;
470                         sigemptyset(&sa.sa_mask);
471                         sa.sa_flags = SA_RESTART;
472
473                         (void) sigaction(SIGDANGER, &sa, NULL);
474 #endif /* _AIX */
475                 }
476 #   endif /* not HAVE_DAEMON */
477 #  else /* SYS_WINNT */
478
479                 {
480                         SERVICE_TABLE_ENTRY dispatchTable[] = {
481                                 { TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main },
482                                 { NULL, NULL }
483                         };
484
485                         /* daemonize */
486                         if (!StartServiceCtrlDispatcher(dispatchTable))
487                         {
488                                 msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m");
489                                 ExitProcess(2);
490                         }
491                 }
492 #  endif /* SYS_WINNT */
493         }
494 # endif /* NODETACH */
495 # if defined(SYS_WINNT) && !defined(NODETACH)
496         else
497                 service_main(argc, argv);
498         return 0;       /* must return a value */
499 } /* end main */
500
501 /*
502  * If this runs as a service under NT, the main thread will block at
503  * StartServiceCtrlDispatcher() and another thread will be started by the
504  * Service Control Dispatcher which will begin execution at the routine
505  * specified in that call (viz. service_main)
506  */
507 void
508 service_main(
509         DWORD argc,
510         LPTSTR *argv
511         )
512 {
513         char *cp;
514         struct recvbuf *rbuflist;
515         struct recvbuf *rbuf;
516 #ifdef AUTOKEY
517         u_int n;
518         char hostname[MAXFILENAME];
519 #endif /* AUTOKEY */
520         if(!debug)
521         {
522                 /* register our service control handler */
523                 if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"),
524                                                                         (LPHANDLER_FUNCTION)service_ctrl)))
525                 {
526                         msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m");
527                         return;
528                 }
529
530                 /* report pending status to Service Control Manager */
531                 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
532                 ssStatus.dwCurrentState = SERVICE_START_PENDING;
533                 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
534                 ssStatus.dwWin32ExitCode = NO_ERROR;
535                 ssStatus.dwServiceSpecificExitCode = 0;
536                 ssStatus.dwCheckPoint = 1;
537                 ssStatus.dwWaitHint = 5000;
538                 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
539                 {
540                         msyslog(LOG_ERR, "SetServiceStatus: %m");
541                         ssStatus.dwCurrentState = SERVICE_STOPPED;
542                         SetServiceStatus(sshStatusHandle, &ssStatus);
543                         return;
544                 }
545
546         }  /* debug */
547 # endif /* defined(SYS_WINNT) && !defined(NODETACH) */
548 #endif /* VMS */
549
550         /*
551          * Logging.  This may actually work on the gizmo board.  Find a name
552          * to log with by using the basename of argv[0]
553          */
554         cp = strrchr(argv[0], '/');
555         if (cp == 0)
556                 cp = argv[0];
557         else
558                 cp++;
559
560         debug = 0; /* will be immediately re-initialized 8-( */
561         getstartup(argc, argv); /* startup configuration, catch logfile this time */
562
563 #if !defined(SYS_WINNT) && !defined(VMS)
564
565 # ifndef LOG_DAEMON
566         openlog(cp, LOG_PID);
567 # else /* LOG_DAEMON */
568
569 #  ifndef LOG_NTP
570 #       define  LOG_NTP LOG_DAEMON
571 #  endif
572         openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
573 #  ifdef DEBUG
574         if (debug)
575                 setlogmask(LOG_UPTO(LOG_DEBUG));
576         else
577 #  endif /* DEBUG */
578                 setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
579 # endif /* LOG_DAEMON */
580 #endif  /* !SYS_WINNT && !VMS */
581
582         NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
583                 msyslog(LOG_NOTICE, "%s", Version);
584
585 #ifdef SYS_WINNT
586         /* GMS 1/18/1997
587          * TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions
588          *
589          process_handle = GetCurrentProcess();
590          if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) {
591          if (VirtualLock(0 , 4194304) == FALSE)
592          msyslog(LOG_ERR, "VirtualLock() failed: %m");
593          } else {
594          msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m");
595          }
596         */
597 #endif /* SYS_WINNT */
598
599 #ifdef SCO5_CLOCK
600         /*
601          * SCO OpenServer's system clock offers much more precise timekeeping
602          * on the base CPU than the other CPUs (for multiprocessor systems),
603          * so we must lock to the base CPU.
604          */
605         {
606             int fd = open("/dev/at1", O_RDONLY);
607             if (fd >= 0) {
608                 int zero = 0;
609                 if (ioctl(fd, ACPU_LOCK, &zero) < 0)
610                     msyslog(LOG_ERR, "cannot lock to base CPU: %m\n");
611                 close( fd );
612             } /* else ...
613                *   If we can't open the device, this probably just isn't
614                *   a multiprocessor system, so we're A-OK.
615                */
616         }
617 #endif
618
619 #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
620         /*
621          * lock the process into memory
622          */
623         if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
624                 msyslog(LOG_ERR, "mlockall(): %m");
625 #else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
626 # ifdef HAVE_PLOCK
627 #  ifdef PROCLOCK
628 #   ifdef _AIX
629         /* 
630          * set the stack limit for AIX for plock().
631          * see get_aix_stack for more info.
632          */
633         if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0)
634         {
635                 msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m");
636         }
637 #   endif /* _AIX */
638         /*
639          * lock the process into memory
640          */
641         if (plock(PROCLOCK) < 0)
642                 msyslog(LOG_ERR, "plock(PROCLOCK): %m");
643 #  else /* not PROCLOCK */
644 #   ifdef TXTLOCK
645         /*
646          * Lock text into ram
647          */
648         if (plock(TXTLOCK) < 0)
649                 msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
650 #   else /* not TXTLOCK */
651         msyslog(LOG_ERR, "plock() - don't know what to lock!");
652 #   endif /* not TXTLOCK */
653 #  endif /* not PROCLOCK */
654 # endif /* HAVE_PLOCK */
655 #endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
656
657         /*
658          * Set up signals we pay attention to locally.
659          */
660 #ifdef SIGDIE1
661         (void) signal_no_reset(SIGDIE1, finish);
662 #endif  /* SIGDIE1 */
663 #ifdef SIGDIE2
664         (void) signal_no_reset(SIGDIE2, finish);
665 #endif  /* SIGDIE2 */
666 #ifdef SIGDIE3
667         (void) signal_no_reset(SIGDIE3, finish);
668 #endif  /* SIGDIE3 */
669 #ifdef SIGDIE4
670         (void) signal_no_reset(SIGDIE4, finish);
671 #endif  /* SIGDIE4 */
672
673 #ifdef SIGBUS
674         (void) signal_no_reset(SIGBUS, finish);
675 #endif /* SIGBUS */
676
677 #if !defined(SYS_WINNT) && !defined(VMS)
678 # ifdef DEBUG
679         (void) signal_no_reset(MOREDEBUGSIG, moredebug);
680         (void) signal_no_reset(LESSDEBUGSIG, lessdebug);
681 # else
682         (void) signal_no_reset(MOREDEBUGSIG, no_debug);
683         (void) signal_no_reset(LESSDEBUGSIG, no_debug);
684 # endif /* DEBUG */
685 #endif /* !SYS_WINNT && !VMS */
686
687         /*
688          * Set up signals we should never pay attention to.
689          */
690 #if defined SIGPIPE
691         (void) signal_no_reset(SIGPIPE, SIG_IGN);
692 #endif  /* SIGPIPE */
693
694 #if defined SYS_WINNT
695         if (!SetConsoleCtrlHandler(OnConsoleEvent, TRUE)) {
696                 msyslog(LOG_ERR, "Can't set console control handler: %m");
697         }
698 #endif
699
700         /*
701          * Call the init_ routines to initialize the data structures.
702          */
703 #if defined (HAVE_IO_COMPLETION_PORT)
704         init_io_completion_port();
705         init_winnt_time();
706 #endif
707         init_auth();
708         init_util();
709         init_restrict();
710         init_mon();
711         init_timer();
712         init_lib();
713         init_random();
714         init_request();
715         init_control();
716         init_peer();
717 #ifdef REFCLOCK
718         init_refclock();
719 #endif
720         set_process_priority();
721         init_proto();           /* Call at high priority */
722         init_io();
723         init_loopfilter();
724         mon_start(MON_ON);      /* monitor on by default now      */
725                                 /* turn off in config if unwanted */
726
727         /*
728          * Get configuration.  This (including argument list parsing) is
729          * done in a separate module since this will definitely be different
730          * for the gizmo board. While at it, save the host name for later
731          * along with the length. The crypto needs this.
732          */
733 #ifdef DEBUG
734         debug = 0;
735 #endif
736         getconfig(argc, argv);
737 #ifdef AUTOKEY
738         gethostname(hostname, MAXFILENAME);
739         n = strlen(hostname) + 1;
740         sys_hostname = emalloc(n);
741         memcpy(sys_hostname, hostname, n);
742 #ifdef PUBKEY
743         crypto_setup();
744 #endif /* PUBKEY */
745 #endif /* AUTOKEY */
746         initializing = 0;
747
748 #if defined(SYS_WINNT) && !defined(NODETACH)
749 # if defined(DEBUG)
750         if(!debug)
751         {
752 # endif
753                 /* report to the service control manager that the service is running */
754                 ssStatus.dwCurrentState = SERVICE_RUNNING;
755                 ssStatus.dwWin32ExitCode = NO_ERROR;
756                 if (!SetServiceStatus(sshStatusHandle, &ssStatus))
757                 {
758                         msyslog(LOG_ERR, "SetServiceStatus: %m");
759                         if (ResolverThreadHandle != NULL)
760                                 CloseHandle(ResolverThreadHandle);
761                         ssStatus.dwCurrentState = SERVICE_STOPPED;
762                         SetServiceStatus(sshStatusHandle, &ssStatus);
763                         return;
764                 }
765 # if defined(DEBUG)
766         }
767 # endif  
768 #endif
769
770         /*
771          * Report that we're up to any trappers
772          */
773         report_event(EVNT_SYSRESTART, (struct peer *)0);
774
775         /*
776          * Use select() on all on all input fd's for unlimited
777          * time.  select() will terminate on SIGALARM or on the
778          * reception of input.  Using select() means we can't do
779          * robust signal handling and we get a potential race
780          * between checking for alarms and doing the select().
781          * Mostly harmless, I think.
782          */
783         /* On VMS, I suspect that select() can't be interrupted
784          * by a "signal" either, so I take the easy way out and
785          * have select() time out after one second.
786          * System clock updates really aren't time-critical,
787          * and - lacking a hardware reference clock - I have
788          * yet to learn about anything else that is.
789          */
790 #if defined(HAVE_IO_COMPLETION_PORT)
791                 WaitHandles[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* exit reques */
792                 WaitHandles[1] = get_timer_handle();
793
794                 for (;;) {
795                         DWORD Index = WaitForMultipleObjectsEx(sizeof(WaitHandles)/sizeof(WaitHandles[0]), WaitHandles, FALSE, 1000, MWMO_ALERTABLE);
796                         switch (Index) {
797                                 case WAIT_OBJECT_0 + 0 : /* exit request */
798                                         exit(0);
799                                 break;
800
801                                 case WAIT_OBJECT_0 + 1 : /* timer */
802                                         timer();
803                                 break;
804                                 case WAIT_OBJECT_0 + 2 : { /* Windows message */
805                                         MSG msg;
806                                         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
807                                                 if (msg.message == WM_QUIT) {
808                                                         exit(0);
809                                                 }
810                                                 DispatchMessage(&msg);
811                                         }
812                                 }
813                                 break;
814
815                                 case WAIT_IO_COMPLETION : /* loop */
816                                 case WAIT_TIMEOUT :
817                                 break;
818                                 
819                         } /* switch */
820                         rbuflist = getrecvbufs();       /* get received buffers */
821
822 #else /* normal I/O */
823
824         was_alarmed = 0;
825         rbuflist = (struct recvbuf *)0;
826         for (;;)
827         {
828 # if !defined(HAVE_SIGNALED_IO) 
829                 extern fd_set activefds;
830                 extern int maxactivefd;
831
832                 fd_set rdfdes;
833                 int nfound;
834 # elif defined(HAVE_SIGNALED_IO)
835                 block_io_and_alarm();
836 # endif
837
838                 rbuflist = getrecvbufs();       /* get received buffers */
839                 if (alarm_flag)         /* alarmed? */
840                 {
841                         was_alarmed = 1;
842                         alarm_flag = 0;
843                 }
844
845                 if (!was_alarmed && rbuflist == (struct recvbuf *)0)
846                 {
847                         /*
848                          * Nothing to do.  Wait for something.
849                          */
850 # ifndef HAVE_SIGNALED_IO
851                         rdfdes = activefds;
852 #  if defined(VMS) || defined(SYS_VXWORKS)
853                         /* make select() wake up after one second */
854                         {
855                                 struct timeval t1;
856
857                                 t1.tv_sec = 1; t1.tv_usec = 0;
858                                 nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
859                                                 (fd_set *)0, &t1);
860                         }
861 #  else
862                         nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
863                                         (fd_set *)0, (struct timeval *)0);
864 #  endif /* VMS */
865                         if (nfound > 0)
866                         {
867                                 l_fp ts;
868
869                                 get_systime(&ts);
870
871                                 (void)input_handler(&ts);
872                         }
873                         else if (nfound == -1 && errno != EINTR)
874                                 msyslog(LOG_ERR, "select() error: %m");
875                         else if (debug > 2) {
876                                 msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
877                         }
878 # else /* HAVE_SIGNALED_IO */
879                         
880                         wait_for_signal();
881 # endif /* HAVE_SIGNALED_IO */
882                         if (alarm_flag)         /* alarmed? */
883                         {
884                                 was_alarmed = 1;
885                                 alarm_flag = 0;
886                         }
887                         rbuflist = getrecvbufs();  /* get received buffers */
888                 }
889 # ifdef HAVE_SIGNALED_IO
890                 unblock_io_and_alarm();
891 # endif /* HAVE_SIGNALED_IO */
892
893                 /*
894                  * Out here, signals are unblocked.  Call timer routine
895                  * to process expiry.
896                  */
897                 if (was_alarmed)
898                 {
899                         timer();
900                         was_alarmed = 0;
901                 }
902
903 #endif /* HAVE_IO_COMPLETION_PORT */
904                 /*
905                  * Call the data procedure to handle each received
906                  * packet.
907                  */
908                 while (rbuflist != (struct recvbuf *)0)
909                 {
910                         rbuf = rbuflist;
911                         rbuflist = rbuf->next;
912                         (rbuf->receiver)(rbuf);
913                         freerecvbuf(rbuf);
914                 }
915 #if defined DEBUG && defined SYS_WINNT
916                 if (debug > 4)
917                     printf("getrecvbufs: %ld handler interrupts, %ld frames\n",
918                            handler_calls, handler_pkts);
919 #endif
920
921                 /*
922                  * Go around again
923                  */
924         }
925         exit(1); /* unreachable */
926         return 1;               /* DEC OSF cc braindamage */
927 }
928
929
930 #ifdef SIGDIE2
931 /*
932  * finish - exit gracefully
933  */
934 static RETSIGTYPE
935 finish(
936         int sig
937         )
938 {
939
940         msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig);
941
942         switch (sig)
943         {
944 # ifdef SIGBUS
945                 case SIGBUS:
946                 printf("\nfinish(SIGBUS)\n");
947                 exit(0);
948 # endif
949                 case 0:                 /* Should never happen... */
950                 return;
951                 default:
952                 exit(0);
953         }
954 }
955 #endif  /* SIGDIE2 */
956
957
958 #ifdef DEBUG
959 /*
960  * moredebug - increase debugging verbosity
961  */
962 static RETSIGTYPE
963 moredebug(
964         int sig
965         )
966 {
967         int saved_errno = errno;
968
969         if (debug < 255)
970         {
971                 debug++;
972                 msyslog(LOG_DEBUG, "debug raised to %d", debug);
973         }
974         errno = saved_errno;
975 }
976
977 /*
978  * lessdebug - decrease debugging verbosity
979  */
980 static RETSIGTYPE
981 lessdebug(
982         int sig
983         )
984 {
985         int saved_errno = errno;
986
987         if (debug > 0)
988         {
989                 debug--;
990                 msyslog(LOG_DEBUG, "debug lowered to %d", debug);
991         }
992         errno = saved_errno;
993 }
994 #else /* not DEBUG */
995 /*
996  * no_debug - We don't do the debug here.
997  */
998 static RETSIGTYPE
999 no_debug(
1000         int sig
1001         )
1002 {
1003         int saved_errno = errno;
1004
1005         msyslog(LOG_DEBUG, "ntpd not compiled for debugging (signal %d)", sig);
1006         errno = saved_errno;
1007 }
1008 #endif  /* not DEBUG */
1009
1010 #ifdef SYS_WINNT
1011 /* service_ctrl - control handler for NTP service
1012  * signals the service_main routine of start/stop requests
1013  * from the control panel or other applications making
1014  * win32API calls
1015  */
1016 void
1017 service_ctrl(
1018         DWORD dwCtrlCode
1019         )
1020 {
1021         DWORD  dwState = SERVICE_RUNNING;
1022
1023         /* Handle the requested control code */
1024         switch(dwCtrlCode)
1025         {
1026                 case SERVICE_CONTROL_PAUSE:
1027                 /* see no reason to support this */
1028                 break;
1029
1030                 case SERVICE_CONTROL_CONTINUE:
1031                 /* see no reason to support this */
1032                 break;
1033
1034                 case SERVICE_CONTROL_STOP:
1035                         dwState = SERVICE_STOP_PENDING;
1036                         /*
1037                          * Report the status, specifying the checkpoint and waithint,
1038                          *      before setting the termination event.
1039                          */
1040                         ssStatus.dwCurrentState = dwState;
1041                         ssStatus.dwWin32ExitCode = NO_ERROR;
1042                         ssStatus.dwWaitHint = 3000;
1043                         if (!SetServiceStatus(sshStatusHandle, &ssStatus))
1044                         {
1045                                 msyslog(LOG_ERR, "SetServiceStatus: %m");
1046                         }
1047                         if (WaitHandles[0] != NULL) {
1048                                 SetEvent(WaitHandles[0]);
1049                         }
1050                 return;
1051
1052                 case SERVICE_CONTROL_INTERROGATE:
1053                 /* Update the service status */
1054                 break;
1055
1056                 default:
1057                 /* invalid control code */
1058                 break;
1059
1060         }
1061
1062         ssStatus.dwCurrentState = dwState;
1063         ssStatus.dwWin32ExitCode = NO_ERROR;
1064         if (!SetServiceStatus(sshStatusHandle, &ssStatus))
1065         {
1066                 msyslog(LOG_ERR, "SetServiceStatus: %m");
1067         }
1068 }
1069
1070 static BOOL WINAPI 
1071 OnConsoleEvent(  
1072         DWORD dwCtrlType
1073         )
1074 {
1075         switch (dwCtrlType) {
1076                 case CTRL_BREAK_EVENT :
1077                         if (debug > 0) {
1078                                 debug <<= 1;
1079                         }
1080                         else {
1081                                 debug = 1;
1082                         }
1083                         if (debug > 8) {
1084                                 debug = 0;
1085                         }
1086                         printf("debug level %d\n", debug);
1087                 break ;
1088
1089                 case CTRL_C_EVENT  :
1090                 case CTRL_CLOSE_EVENT :
1091                 case CTRL_SHUTDOWN_EVENT :
1092                         if (WaitHandles[0] != NULL) {
1093                                 SetEvent(WaitHandles[0]);
1094                         }
1095                 break;
1096
1097                 default :
1098                         return FALSE;
1099
1100
1101         }
1102         return TRUE;;
1103 }
1104
1105
1106 /*
1107  *  NT version of exit() - all calls to exit() should be routed to
1108  *  this function.
1109  */
1110 void
1111 service_exit(
1112         int status
1113         )
1114 {
1115         if (!debug) { /* did not become a service, simply exit */
1116                 /* service mode, need to have the service_main routine
1117                  * register with the service control manager that the 
1118                  * service has stopped running, before exiting
1119                  */
1120                 ssStatus.dwCurrentState = SERVICE_STOPPED;
1121                 SetServiceStatus(sshStatusHandle, &ssStatus);
1122
1123         }
1124         uninit_io_completion_port();
1125         reset_winnt_time();
1126
1127 # if defined _MSC_VER
1128         _CrtDumpMemoryLeaks();
1129 # endif 
1130 #undef exit     
1131         exit(status);
1132 }
1133
1134 #endif /* SYS_WINNT */