ntpd.c revision 56746
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 */
113HANDLE ResolverThreadHandle = NULL;
114/* variables used to inform the Service Control Manager of our current state */
115SERVICE_STATUS ssStatus;
116SERVICE_STATUS_HANDLE	sshStatusHandle;
117HANDLE WaitHandles[2] = { NULL, NULL };
118char szMsgPath[255];
119static 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 */
130volatile int debug;
131
132/*
133 * No-fork flag.  If set, we do not become a background daemon.
134 */
135int nofork;
136
137/*
138 * Initializing flag.  All async routines watch this and only do their
139 * thing when it is clear.
140 */
141int initializing;
142
143/*
144 * Version declaration
145 */
146extern const char *Version;
147
148int was_alarmed;
149
150#ifdef DECL_SYSCALL
151/*
152 * We put this here, since the argument profile is syscall-specific
153 */
154extern int syscall	P((int, ...));
155#endif /* DECL_SYSCALL */
156
157
158#ifdef	SIGDIE2
159static	RETSIGTYPE	finish		P((int));
160#endif	/* SIGDIE2 */
161
162#ifdef	DEBUG
163static	RETSIGTYPE	moredebug	P((int));
164static	RETSIGTYPE	lessdebug	P((int));
165#else /* not DEBUG */
166static	RETSIGTYPE	no_debug	P((int));
167#endif	/* not DEBUG */
168
169int 		ntpdmain		P((int, char **));
170static void	set_process_priority	P((void));
171
172
173#ifdef NO_MAIN_ALLOWED
174CALL(ntpd,"ntpd",ntpdmain);
175#else
176int
177main(
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 */
201static char *
202get_aix_stack(void)
203{
204	char ch;
205	return (&ch);
206}
207
208/*
209 * Signal handler for SIGDANGER.
210 */
211static void
212catch_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 */
223static void
224set_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 */
330int
331ntpdmain(
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 */
507void
508service_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 */
922static RETSIGTYPE
923finish(
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 */
950static RETSIGTYPE
951moredebug(
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 */
968static RETSIGTYPE
969lessdebug(
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 */
986static RETSIGTYPE
987no_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 */
1004void
1005service_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
1058static BOOL WINAPI
1059OnConsoleEvent(
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 */
1098void
1099service_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