xref: /freebsd/contrib/ntp/ntpd/ntpd.c (revision 224ba2bd37e182b64f7d78defef8a6cacaad3415)
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 */
1135