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