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