NetBSD/usr.sbin/xntp/xntpd/ntpd.c

932 lines
22 KiB
C

/* $NetBSD: ntpd.c,v 1.2 1998/01/09 06:06:47 perry Exp $ */
/*
* ntpd.c - main program for the fixed point NTP daemon
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <stdio.h>
#include <errno.h>
#ifndef SYS_WINNT
# if !defined(VMS) /*wjm*/
# include <sys/param.h>
# endif /* VMS */
# include <sys/signal.h>
# ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
# endif /* HAVE_SYS_IOCTL_H */
# include <sys/time.h>
# if !defined(VMS) /*wjm*/
# include <sys/resource.h>
# endif /* VMS */
#else
# include <signal.h>
# include <process.h>
# include <io.h>
# include "../libntp/log.h"
#endif /* SYS_WINNT */
#if defined(HAVE_RTPRIO)
# ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
# endif
# ifdef HAVE_SYS_LOCK_H
# include <sys/lock.h>
# endif
# include <sys/rtprio.h>
#endif
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
#ifdef SYS_DOMAINOS
# include <apollo/base.h>
#endif /* SYS_DOMAINOS */
#include "ntpd.h"
#include "ntp_select.h"
#include "ntp_io.h"
#include "ntp_stdlib.h"
#if 0 /* HMS: I don't think we need this. 961223 */
#ifdef LOCK_PROCESS
# ifdef SYS_SOLARIS
# include <sys/mman.h>
# else
# include <sys/lock.h>
# endif
#endif
#endif
/*
* Signals we catch for debugging. If not debugging we ignore them.
*/
#define MOREDEBUGSIG SIGUSR1
#define LESSDEBUGSIG SIGUSR2
/*
* Signals which terminate us gracefully.
*/
#ifndef SYS_WINNT
#define SIGDIE1 SIGHUP
#endif /* SYS_WINNT */
#define SIGDIE2 SIGINT
#ifndef SYS_WINNT
#define SIGDIE3 SIGQUIT
#endif /* SYS_WINNT */
#define SIGDIE4 SIGTERM
#ifdef SYS_WINNT
/* handles for various threads, process, and objects */
extern HANDLE hServDoneEvent;
HANDLE process_handle = NULL, WorkerThreadHandle = NULL,
ResolverThreadHandle = NULL, TimerThreadHandle = NULL,
hMutex = NULL;
/* variables used to inform the Service Control Manager of our current state */
SERVICE_STATUS ssStatus;
SERVICE_STATUS_HANDLE sshStatusHandle;
int was_stopped = 0;
char szMsgPath[255];
#endif /* SYS_WINNT */
/*
* Scheduling priority we run at
*/
#define NTPD_PRIO (-12)
/*
* Debugging flag
*/
volatile int debug;
/*
* -x and -g flags
*/
extern int allow_set_backward;
int correct_any;
/*
* Initializing flag. All async routines watch this and only do their
* thing when it is clear.
*/
int initializing;
/*
* Version declaration
*/
extern char *Version;
/* Added mutex to prevent race condition among threads under Windows NT */
#ifdef SYS_WINNT
HANDLE m_hListMutex;
#endif /* SYS_WINNT */
/*
* Alarm flag. Imported from timer module
*/
extern int alarm_flag;
int was_alarmed;
#ifdef DECL_SYSCALL
/*
* We put this here, since the argument profile is syscall-specific
*/
extern int syscall P((int, struct timeval *, struct timeval *));
#endif /* DECL_SYSCALL */
#ifdef SYS_WINNT
extern void worker_thread(void *);
#endif /* SYS_WINNT */
#ifdef SIGDIE2
static RETSIGTYPE finish P((int));
#endif /* SIGDIE2 */
#ifdef DEBUG
static RETSIGTYPE moredebug P((int));
static RETSIGTYPE lessdebug P((int));
#else /* not DEBUG */
static RETSIGTYPE no_debug P((int));
#endif /* not DEBUG */
/*
* Main program. Initialize us, disconnect us from the tty if necessary,
* and loop waiting for I/O and/or timer expiries.
*/
#if !defined(VMS)
void
#endif /* VMS */
main(argc, argv)
int argc;
char *argv[];
{
#ifndef SYS_WINNT
char *cp;
struct recvbuf *rbuflist;
struct recvbuf *rbuf;
#endif
initializing = 1; /* mark that we are initializing */
debug = 0; /* no debugging by default */
{
int uv;
uv = umask(0);
if(uv)
(void) umask(uv);
else
(void) umask(022);
}
#ifdef HAVE_GETUID
{
uid_t uid;
uid = getuid();
if (uid)
{
msyslog(LOG_ERR, "xntpd: must be run as root, not uid %d", uid);
exit(1);
}
}
#endif
#ifdef SYS_WINNT
/* Set the Event-ID message-file name. */
if (!ExpandEnvironmentStrings("%windir%\\system32\\xntpd.exe", szMsgPath, sizeof(szMsgPath))) {
msyslog(LOG_ERR, "ExpandEnvironmentStrings(PGM_EXE_FILE) failed: %m\n");
exit(1);
}
addSourceToRegistry("NTP", szMsgPath);
#endif
getstartup(argc, argv); /* startup configuration, may set debug */
#if !defined(VMS)
# ifndef NODETACH
/*
* Detach us from the terminal. May need an #ifndef GIZMO.
*/
# ifdef DEBUG
if (!debug)
{
# endif /* DEBUG */
# ifndef SYS_WINNT
# ifdef HAVE_DAEMON
daemon(0, 0);
# else /* not HAVE_DAEMON */
if (fork())
exit(0);
{
u_long s;
int max_fd;
#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
max_fd = sysconf(_SC_OPEN_MAX);
#else /* HAVE_SYSCONF && _SC_OPEN_MAX */
max_fd = getdtablesize();
#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
for (s = 0; s < max_fd; s++)
(void) close(s);
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
#ifdef SYS_DOMAINOS
{
uid_$t puid;
status_$t st;
proc2_$who_am_i(&puid);
proc2_$make_server(&puid, &st);
}
#endif /* SYS_DOMAINOS */
#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
# ifdef HAVE_SETSID
if (setsid() == (pid_t)-1)
msyslog(LOG_ERR, "xntpd: setsid(): %m");
# else
if (setpgid(0, 0) == -1)
msyslog(LOG_ERR, "xntpd: setpgid(): %m");
# endif
#else /* HAVE_SETPGID || HAVE_SETSID */
{
int fid;
fid = open("/dev/tty", 2);
if (fid >= 0)
{
(void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
(void) close(fid);
}
# ifdef HAVE_SETPGRP_O
(void) setpgrp();
# else /* HAVE_SETPGRP_0 */
(void) setpgrp(0, getpid());
# endif /* HAVE_SETPGRP_0 */
}
#endif /* HAVE_SETPGID || HAVE_SETSID */
}
#endif /* not HAVE_DAEMON */
#else /* SYS_WINNT */
{
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ TEXT("NetworkTimeProtocol"), (LPSERVICE_MAIN_FUNCTION)service_main },
{ NULL, NULL }
};
/* daemonize */
if (!StartServiceCtrlDispatcher(dispatchTable))
{
if (!was_stopped)
{
msyslog(LOG_ERR, "StartServiceCtrlDispatcher: %m");
ExitProcess(2);
}
else
{
NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
msyslog(LOG_INFO, "StartServiceCtrlDispatcher: service stopped");
ExitProcess(0);
}
}
}
#endif /* SYS_WINNT */
#ifdef DEBUG
}
#endif /* DEBUG */
#endif /* NODETACH */
#if defined(SYS_WINNT) && !defined(NODETACH)
#if defined(DEBUG)
else
service_main(argc, argv);
#endif
} /* end main */
/*
* If this runs as a service under NT, the main thread will block at
* StartServiceCtrlDispatcher() and another thread will be started by the
* Service Control Dispatcher which will begin execution at the routine
* specified in that call (viz. service_main)
*/
void
service_main(argc, argv)
DWORD argc;
LPTSTR *argv;
{
char *cp;
DWORD dwWait;
if(!debug)
{
/* register our service control handler */
if (!(sshStatusHandle = RegisterServiceCtrlHandler( TEXT("NetworkTimeProtocol"),
(LPHANDLER_FUNCTION)service_ctrl)))
{
msyslog(LOG_ERR, "RegisterServiceCtrlHandler failed: %m");
return;
}
/* report pending status to Service Control Manager */
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwCurrentState = SERVICE_START_PENDING;
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ssStatus.dwWin32ExitCode = NO_ERROR;
ssStatus.dwServiceSpecificExitCode = 0;
ssStatus.dwCheckPoint = 1;
ssStatus.dwWaitHint = 5000;
if (!SetServiceStatus(sshStatusHandle, &ssStatus))
{
msyslog(LOG_ERR, "SetServiceStatus: %m");
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
}
/*
* create an event object that the control handler function
* will signal when it receives the "stop" control code
*/
if (!(hServDoneEvent = CreateEvent(
NULL, /* no security attributes */
TRUE, /* manual reset event */
FALSE, /* not-signalled */
NULL))) /* no name */
{
msyslog(LOG_ERR, "CreateEvent failed: %m");
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
}
} /* debug */
#endif /* defined(SYS_WINNT) && !defined(NODETACH) */
#endif /* VMS */
/*
* Logging. This may actually work on the gizmo board. Find a name
* to log with by using the basename of argv[0]
*/
cp = strrchr(argv[0], '/');
if (cp == 0)
cp = argv[0];
else
cp++;
debug = 0; /* will be immediately re-initialized 8-( */
getstartup(argc, argv); /* startup configuration, catch logfile this time */
#if !defined(SYS_WINNT) && !defined(VMS)
# ifndef LOG_DAEMON
openlog(cp, LOG_PID);
# else /* LOG_DAEMON */
# ifndef LOG_NTP
# define LOG_NTP LOG_DAEMON
# endif
openlog(cp, LOG_PID | LOG_NDELAY, LOG_NTP);
# ifdef DEBUG
if (debug)
setlogmask(LOG_UPTO(LOG_DEBUG));
else
# endif /* DEBUG */
setlogmask(LOG_UPTO(LOG_DEBUG)); /* @@@ was INFO */
# endif /* LOG_DAEMON */
#endif /* !SYS_WINNT && !VMS */
NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */
msyslog(LOG_NOTICE, "%s", Version);
#ifdef SYS_WINNT
/* GMS 1/18/1997
* TODO: lock the process in memory using SetProcessWorkingSetSize() and VirtualLock() functions
*
process_handle = GetCurrentProcess();
if (SetProcessWorkingSetSize(process_handle, 2097152 , 4194304 ) == TRUE) {
if (VirtualLock(0 , 4194304) == FALSE)
msyslog(LOG_ERR, "VirtualLock() failed: %m");
} else {
msyslog(LOG_ERR, "SetProcessWorkingSetSize() failed: %m");
}
*/
#endif /* SYS_WINNT */
#if defined(HAVE_RTPRIO)
# ifdef TXTLOCK
/*
* Lock text into ram, set real time priority
*/
if (plock(TXTLOCK) < 0)
msyslog(LOG_ERR, "plock() error: %m");
# endif
# ifdef RTP_SET
{
struct rtprio srtp;
srtp.type = RTP_PRIO_REALTIME; /* was: RTP_PRIO_NORMAL */
srtp.prio = 0; /* 0 (hi) -> RTP_PRIO_MAX (31,lo) */
if (rtprio(RTP_SET, getpid(), &srtp) < 0)
msyslog(LOG_ERR, "rtprio() error: %m");
}
# else /* not RTP_SET */
if (rtprio(0, 120) < 0)
msyslog(LOG_ERR, "rtprio() error: %m");
# endif /* not RTP_SET */
#else /* not HAVE_RTPRIO */
# if defined(LOCK_PROCESS)
# if defined(MCL_CURRENT) && defined(MCL_FUTURE)
/*
* lock the process into memory
*/
if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
msyslog(LOG_ERR, "mlockall(): %m");
# else /* not (MCL_CURRENT && MCL_FUTURE) */
# if defined(PROCLOCK)
/*
* lock the process into memory
*/
if (plock(PROCLOCK) < 0)
msyslog(LOG_ERR, "plock(): %m");
# endif /* PROCLOCK */
# endif /* not (MCL_CURRENT && MCL_FUTURE) */
# endif /* LOCK_PROCESS */
# if defined(NTPD_PRIO) && NTPD_PRIO != 0
/*
* Set the priority.
*/
# ifdef HAVE_ATT_NICE
nice (NTPD_PRIO);
# endif /* HAVE_ATT_NICE */
# ifdef HAVE_BSD_NICE
(void) setpriority(PRIO_PROCESS, 0, NTPD_PRIO);
# endif /* HAVE_BSD_NICE */
# endif /* NTPD_PRIO && NTPD_PRIO != 0 */
#endif /* not HAVE RTP_PRIO */
#ifdef SYS_WINNT
process_handle = GetCurrentProcess();
if (!SetPriorityClass(process_handle, (DWORD) REALTIME_PRIORITY_CLASS))
{
msyslog(LOG_ERR, "SetPriorityClass: %m");
}
/* Added mutex to prevent race condition among threads under Windows NT */
if ((m_hListMutex = CreateMutex(NULL,FALSE,NULL)) == NULL)
msyslog(LOG_ERR, "CreateMutex: %m");
#else /* not SYS_WINNT */
/*
* Set up signals we pay attention to locally.
*/
# ifdef SIGDIE1
(void) signal_no_reset(SIGDIE1, finish);
# endif /* SIGDIE1 */
# ifdef SIGDIE2
(void) signal_no_reset(SIGDIE2, finish);
# endif /* SIGDIE2 */
# ifdef SIGDIE3
(void) signal_no_reset(SIGDIE3, finish);
# endif /* SIGDIE3 */
# ifdef SIGDIE4
(void) signal_no_reset(SIGDIE4, finish);
# endif /* SIGDIE4 */
#endif /* not SYS_WINNT */
#ifdef SIGBUS
(void) signal_no_reset(SIGBUS, finish);
#endif /* SIGBUS */
#if !defined(SYS_WINNT) && !defined(VMS)
# ifdef DEBUG
(void) signal_no_reset(MOREDEBUGSIG, moredebug);
(void) signal_no_reset(LESSDEBUGSIG, lessdebug);
# else
(void) signal_no_reset(MOREDEBUGSIG, no_debug);
(void) signal_no_reset(LESSDEBUGSIG, no_debug);
# endif /* DEBUG */
#endif /* !SYS_WINNT && !VMS */
/*
* Set up signals we should never pay attention to.
*/
#ifdef SIGPIPE
(void) signal_no_reset(SIGPIPE, SIG_IGN);
#endif /* SIGPIPE */
/*
* Call the init_ routines to initialize the data structures.
* Note that init_systime() may run a protocol to get a crude
* estimate of the time as an NTP client when running on the
* gizmo board. It is important that this be run before
* init_subs() since the latter uses the time of day to seed
* the random number generator. That is not the only
* dependency between these, either, be real careful about
* reordering.
*/
init_auth();
init_util();
init_restrict();
init_mon();
init_systime();
init_timer();
init_lib();
init_random();
init_request();
init_control();
init_leap();
init_peer();
#ifdef REFCLOCK
init_refclock();
#endif
init_proto();
init_io();
init_loopfilter();
mon_start(MON_ON); /* monitor on by default now */
/* turn off in config if unwanted */
/*
* Get configuration. This (including argument list parsing) is
* done in a separate module since this will definitely be different
* for the gizmo board.
*/
getconfig(argc, argv);
initializing = 0;
#if defined(SYS_WINNT) && !defined(NODETACH)
# if defined(DEBUG)
if(!debug)
{
# endif
/*
* the service_main() thread will have to wait for requests to
* start/stop/pause/continue from the services icon in the Control
* Panel or from any WIN32 application start a new thread to perform
* all the work of the NTP service
*/
if (!(WorkerThreadHandle = (HANDLE)_beginthread(
worker_thread,
0, /* stack size */
NULL))) /* argument to thread */
{
msyslog(LOG_ERR, "_beginthread: %m");
if (hServDoneEvent != NULL)
CloseHandle(hServDoneEvent);
if (ResolverThreadHandle != NULL)
CloseHandle(ResolverThreadHandle);
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
}
/* report to the service control manager that the service is running */
ssStatus.dwCurrentState = SERVICE_RUNNING;
ssStatus.dwWin32ExitCode = NO_ERROR;
if (!SetServiceStatus(sshStatusHandle, &ssStatus))
{
msyslog(LOG_ERR, "SetServiceStatus: %m");
if (hServDoneEvent != NULL)
CloseHandle(hServDoneEvent);
if (ResolverThreadHandle != NULL)
CloseHandle(ResolverThreadHandle);
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
}
/* wait indefinitely until hServDoneEvent is signaled */
dwWait = WaitForSingleObject(hServDoneEvent,INFINITE);
if (hServDoneEvent != NULL)
CloseHandle(hServDoneEvent);
if (ResolverThreadHandle != NULL)
CloseHandle(ResolverThreadHandle);
if (WorkerThreadHandle != NULL)
CloseHandle(WorkerThreadHandle);
if (TimerThreadHandle != NULL)
CloseHandle(TimerThreadHandle);
/* restore the clock frequency back to its original value */
if (!SetSystemTimeAdjustment((DWORD)0, TRUE))
msyslog(LOG_ERR, "Failed to reset clock frequency, SetSystemTimeAdjustment(): %m");
ssStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(sshStatusHandle, &ssStatus);
return;
# if defined(DEBUG)
}
else
worker_thread( (void *) 0 );
# endif
} /* end service_main() */
/*
* worker_thread - perform all remaining functions after initialization and and becoming a service
*/
void
worker_thread(notUsed)
void *notUsed;
{
struct recvbuf *rbuflist;
struct recvbuf *rbuf;
#endif /* defined(SYS_WINNT) && !defined(NODETACH) */
/*
* Report that we're up to any trappers
*/
report_event(EVNT_SYSRESTART, (struct peer *)0);
/*
* Use select() on all on all input fd's for unlimited
* time. select() will terminate on SIGALARM or on the
* reception of input. Using select() means we can't do
* robust signal handling and we get a potential race
* between checking for alarms and doing the select().
* Mostly harmless, I think.
*/
/*
* Under NT, a timer periodically invokes a callback function
* on a different thread. This callback function has no way
* of interrupting a winsock "select" call on a different
* thread. A mutex is used to synchronize access to clock
* related variables between the two threads (one blocking
* on a select or processing the received packets and the
* other that calls the timer callback function, timer(),
* every second). Due to this change, timer() routine can
* be invoked between processing two or more received
* packets, or even during processing a single received
* packet before entering the clock_update routine (if
* needed). The potential race condition is also avoided.
*/
/* On VMS, I suspect that select() can't be interrupted
* by a "signal" either, so I take the easy way out and
* have select() time out after one second.
* System clock updates really aren't time-critical,
* and - lacking a hardware reference clock - I have
* yet to learn about anything else that is.
*/
was_alarmed = 0;
rbuflist = (struct recvbuf *)0;
for (;;)
{
#ifndef HAVE_SIGNALED_IO
extern fd_set activefds;
extern int maxactivefd;
fd_set rdfdes;
int nfound;
#else
block_io_and_alarm();
#endif
rbuflist = getrecvbufs(); /* get received buffers */
if (alarm_flag) /* alarmed? */
{
was_alarmed = 1;
alarm_flag = 0;
}
if (!was_alarmed && rbuflist == (struct recvbuf *)0)
{
/*
* Nothing to do. Wait for something.
*/
#ifndef HAVE_SIGNALED_IO
rdfdes = activefds;
#if defined(VMS)
/* make select() wake up after one second */
{
struct timeval t1;
t1.tv_sec = 1; t1.tv_usec = 0;
nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
(fd_set *)0, &t1);
}
#else
nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
(fd_set *)0, (struct timeval *)0);
#endif /* VMS */
if (nfound > 0)
{
l_fp ts;
get_systime(&ts);
(void)input_handler(&ts);
}
else if (
#ifndef SYS_WINNT
(nfound == -1 && errno != EINTR)
#else /* SYS_WINNT */
(nfound == SOCKET_ERROR && WSAGetLastError() != WSAEINTR)
#endif /* SYS_WINNT */
)
msyslog(LOG_ERR, "select() error: %m");
else if (debug)
msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
#else
wait_for_signal();
#endif
if (alarm_flag) /* alarmed? */
{
was_alarmed = 1;
alarm_flag = 0;
}
rbuflist = getrecvbufs(); /* get received buffers */
}
#ifdef HAVE_SIGNALED_IO
unblock_io_and_alarm();
#endif /* HAVE_SIGNALED_IO */
/*
* Out here, signals are unblocked. Call timer routine
* to process expiry.
*/
#ifndef SYS_WINNT
/*
* under WinNT, the timer() routine is directly called
* by the timer callback function (alarming)
* was_alarmed should have never been set, but don't
* want to risk timer() being accidently called here
*/
if (was_alarmed)
{
timer();
was_alarmed = 0;
}
#endif /* SYS_WINNT */
/*
* Call the data procedure to handle each received
* packet.
*/
while (rbuflist != (struct recvbuf *)0)
{
rbuf = rbuflist;
rbuflist = rbuf->next;
(rbuf->receiver)(rbuf);
freerecvbuf(rbuf);
}
/*
* Go around again
*/
}
}
#ifdef SIGDIE2
/*
* finish - exit gracefully
*/
static RETSIGTYPE
finish(sig)
int sig;
{
msyslog(LOG_NOTICE, "xntpd exiting on signal %d", sig);
#ifdef SYS_WINNT
/*
* with any exit(0)'s in the worker_thread, the service_main()
* thread needs to be informed to quit also
*/
SetEvent(hServDoneEvent);
#endif /* SYS_WINNT */
switch (sig)
{
#ifdef SIGBUS
case SIGBUS:
#endif
case 0: /* Should never happen... */
return;
default:
exit(0);
}
}
#endif /* SIGDIE2 */
#ifdef DEBUG
/*
* moredebug - increase debugging verbosity
*/
static RETSIGTYPE
moredebug(sig)
int sig;
{
int saved_errno = errno;
if (debug < 255)
{
debug++;
msyslog(LOG_DEBUG, "debug raised to %d", debug);
}
errno = saved_errno;
}
/*
* lessdebug - decrease debugging verbosity
*/
static RETSIGTYPE
lessdebug(sig)
int sig;
{
int saved_errno = errno;
if (debug > 0)
{
debug--;
msyslog(LOG_DEBUG, "debug lowered to %d", debug);
}
errno = saved_errno;
}
#else /* not DEBUG */
/*
* no_debug - We don't do the debug here.
*/
static RETSIGTYPE
no_debug(sig)
int sig;
{
int saved_errno = errno;
msyslog(LOG_DEBUG, "xntpd not compiled for debugging (signal %d)", sig);
errno = saved_errno;
}
#endif /* not DEBUG */
#ifdef SYS_WINNT
/* service_ctrl - control handler for NTP service
* signals the service_main routine of start/stop requests
* from the control panel or other applications making
* win32API calls
*/
void
service_ctrl(dwCtrlCode)
DWORD dwCtrlCode;
{
DWORD dwState = SERVICE_RUNNING;
/* Handle the requested control code */
switch(dwCtrlCode)
{
case SERVICE_CONTROL_PAUSE:
/* see no reason to support this */
break;
case SERVICE_CONTROL_CONTINUE:
/* see no reason to support this */
break;
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
/*
* Report the status, specifying the checkpoint and waithint,
* before setting the termination event.
*/
ssStatus.dwCurrentState = dwState;
ssStatus.dwWin32ExitCode = NO_ERROR;
ssStatus.dwWaitHint = 3000;
if (!SetServiceStatus(sshStatusHandle, &ssStatus))
{
msyslog(LOG_ERR, "SetServiceStatus: %m");
}
was_stopped = 1;
SetEvent(hServDoneEvent);
return;
case SERVICE_CONTROL_INTERROGATE:
/* Update the service status */
break;
default:
/* invalid control code */
break;
}
ssStatus.dwCurrentState = dwState;
ssStatus.dwWin32ExitCode = NO_ERROR;
if (!SetServiceStatus(sshStatusHandle, &ssStatus))
{
msyslog(LOG_ERR, "SetServiceStatus: %m");
}
}
#endif /* SYS_WINNT */