xref: /freebsd/contrib/ntp/ntpd/ntpd.c (revision d37ea99837e6ad50837fd9fe1771ddf1c3ba6002)
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 */
124 HANDLE ResolverThreadHandle = NULL;
125 /* variables used to inform the Service Control Manager of our current state */
126 SERVICE_STATUS ssStatus;
127 SERVICE_STATUS_HANDLE	sshStatusHandle;
128 HANDLE WaitHandles[3] = { NULL, NULL, NULL };
129 char szMsgPath[255];
130 static BOOL WINAPI OnConsoleEvent(DWORD dwCtrlType);
131 #endif /* SYS_WINNT */
132 
133 /*
134  * Scheduling priority we run at
135  */
136 #define NTPD_PRIO	(-12)
137 
138 int 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  */
146 volatile int debug;
147 
148 /*
149  * No-fork flag.  If set, we do not become a background daemon.
150  */
151 int nofork;
152 
153 /*
154  * Initializing flag.  All async routines watch this and only do their
155  * thing when it is clear.
156  */
157 int initializing;
158 
159 /*
160  * Version declaration
161  */
162 extern const char *Version;
163 
164 int was_alarmed;
165 
166 #ifdef DECL_SYSCALL
167 /*
168  * We put this here, since the argument profile is syscall-specific
169  */
170 extern int syscall	P((int, ...));
171 #endif /* DECL_SYSCALL */
172 
173 
174 #ifdef	SIGDIE2
175 static	RETSIGTYPE	finish		P((int));
176 #endif	/* SIGDIE2 */
177 
178 #ifdef	DEBUG
179 static	RETSIGTYPE	moredebug	P((int));
180 static	RETSIGTYPE	lessdebug	P((int));
181 #else /* not DEBUG */
182 static	RETSIGTYPE	no_debug	P((int));
183 #endif	/* not DEBUG */
184 
185 int 		ntpdmain		P((int, char **));
186 static void	set_process_priority	P((void));
187 
188 
189 #ifdef NO_MAIN_ALLOWED
190 CALL(ntpd,"ntpd",ntpdmain);
191 #else
192 int
193 main(
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  */
217 static char *
218 get_aix_stack(void)
219 {
220 	char ch;
221 	return (&ch);
222 }
223 
224 /*
225  * Signal handler for SIGDANGER.
226  */
227 static void
228 catch_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  */
239 static void
240 set_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  */
330 int
331 ntpdmain(
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  */
514 void
515 service_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  */
962 static RETSIGTYPE
963 finish(
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  */
990 static RETSIGTYPE
991 moredebug(
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  */
1008 static RETSIGTYPE
1009 lessdebug(
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  */
1026 static RETSIGTYPE
1027 no_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  */
1044 void
1045 service_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 
1098 static BOOL WINAPI
1099 OnConsoleEvent(
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  */
1138 void
1139 service_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 */
1163