ntpd.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright (c) 1996-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#define HAVE_POSIX_MMAN
/*
* ntpd.c - main program for the fixed point NTP daemon
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#endif
#include <stdio.h>
#include <errno.h>
#ifndef SYS_WINNT
# if !defined(VMS) /*wjm*/
# endif /* VMS */
# ifdef HAVE_SYS_IOCTL_H
# endif /* HAVE_SYS_IOCTL_H */
# if !defined(VMS) /*wjm*/
# include <sys/resource.h>
# endif /* VMS */
#else
# include <signal.h>
# include <process.h>
# include <io.h>
#endif /* SYS_WINNT */
#if defined(HAVE_RTPRIO)
# ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
# endif
# ifdef HAVE_SYS_LOCK_H
# endif
#else
# ifdef HAVE_PLOCK
# ifdef HAVE_SYS_LOCK_H
# endif
# endif
#endif
#if defined(HAVE_SCHED_SETSCHEDULER)
# include <sched.h>
#endif
#if defined(HAVE_SYS_MMAN_H)
#endif
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
#ifdef SYS_DOMAINOS
#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
# else
# 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
#endif /* SYS_WINNT */
#ifdef SYS_WINNT
/* handles for various threads, process, and objects */
extern HANDLE hServDoneEvent;
/* variables used to inform the Service Control Manager of our current state */
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
#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
*/
#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 */
#ifdef NO_MAIN_ALLOWED
void xntpdmain P((int, char *[]));
#else
int main P((int, char *[]));
#endif
/*
* Main program. Initialize us, disconnect us from the tty if necessary,
*/
#ifndef NO_MAIN_ALLOWED
int main
#else
void xntpdmain
#endif
int argc;
char *argv[];
{
#ifndef SYS_WINNT
char *cp;
# if defined (SYS_SOLARIS)
# define N_FD_RESERVE 16
int fdsave[N_FD_RESERVE], f;
# endif
#endif
debug = 0; /* no debugging by default */
#ifdef HAVE_UMASK
/* vxWorks does not have umask */
{
int uv;
if(uv)
else
(void) umask(022);
}
#endif
#ifdef HAVE_GETUID
{
if (uid)
{
exit(1);
}
}
#endif
#ifdef SYS_WINNT
/* Set the Event-ID message-file name. */
exit(1);
}
#endif
#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);
{
#if defined(SYS_SOLARIS)
closefrom(0);
#else /* SYS_SOLARIS */
u_long s;
int max_fd;
#if defined(HAVE_SYSCONF) && defined(_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);
#endif /* SYS_SOLARIS */
(void) open("/", 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
#ifdef SYS_DOMAINOS
{
}
#endif /* SYS_DOMAINOS */
#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
# ifdef HAVE_SETSID
# else
if (setpgid(0, 0) == -1)
# endif
#else /* HAVE_SETPGID || HAVE_SETSID */
{
int fid;
if (fid >= 0)
{
}
# ifdef HAVE_SETPGRP_O
(void) setpgrp();
# else /* HAVE_SETPGRP_0 */
# endif /* HAVE_SETPGRP_0 */
}
#endif /* HAVE_SETPGID || HAVE_SETSID */
}
#endif /* not HAVE_DAEMON */
#else /* SYS_WINNT */
{
};
/* daemonize */
{
if (!was_stopped)
{
ExitProcess(2);
}
else
{
ExitProcess(0);
}
}
}
#endif /* SYS_WINNT */
#ifdef DEBUG
}
#endif /* DEBUG */
#endif /* NODETACH */
#if defined(DEBUG)
else
#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
{
char *cp;
if(!debug)
{
/* register our service control handler */
{
return;
}
/* report pending status to Service Control Manager */
{
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 */
{
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]
*/
if (cp == 0)
else
cp++;
debug = 0; /* will be immediately re-initialized 8-( */
# ifndef LOG_DAEMON
# else /* LOG_DAEMON */
# ifndef LOG_NTP
# define LOG_NTP LOG_DAEMON
# endif
# ifdef DEBUG
if (debug)
else
# endif /* DEBUG */
# endif /* LOG_DAEMON */
#endif /* !SYS_WINNT && !VMS */
#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 */
/*
* lock the process into memory
*/
#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
# ifdef HAVE_PLOCK
# ifdef PROCLOCK
/*
* lock the process into memory
*/
# else /* not PROCLOCK */
# ifdef TXTLOCK
/*
* Lock text into ram
*/
# else /* not TXTLOCK */
# endif /* not TXTLOCK */
# endif /* not PROCLOCK */
# endif /* HAVE_PLOCK */
#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
/*
* Set the priority.
*/
#ifdef SYS_WINNT
{
}
/* Added mutex to prevent race condition among threads under Windows NT */
#else /* not SYS_WINNT */
# if defined(HAVE_SCHED_SETSCHEDULER)
{
struct sched_param sched;
{
}
}
# else /* not HAVE_SCHED_SETSCHEDULER */
# if defined(HAVE_RTPRIO)
# ifdef RTP_SET
{
}
# else /* not RTP_SET */
if (rtprio(0, 120) < 0)
# endif /* not RTP_SET */
# else /* not HAVE_RTPRIO */
# ifdef HAVE_ATT_NICE
# endif /* HAVE_ATT_NICE */
# ifdef HAVE_BSD_NICE
# endif /* HAVE_BSD_NICE */
# endif /* NTPD_PRIO && NTPD_PRIO != 0 */
# endif /* not HAVE_RTPRIO */
# endif /* not HAVE_SCHED_SETSCHEDULER */
#endif /* not SYS_WINNT */
/*
* Set up signals we pay attention to locally.
*/
# ifdef SIGDIE1
# endif /* SIGDIE1 */
# ifdef SIGDIE2
# endif /* SIGDIE2 */
# ifdef SIGDIE3
# endif /* SIGDIE3 */
# ifdef SIGDIE4
# endif /* SIGDIE4 */
#ifdef SIGBUS
#endif /* SIGBUS */
# ifdef DEBUG
# else
# endif /* DEBUG */
#endif /* !SYS_WINNT && !VMS */
/*
* Set up signals we should never pay attention to.
*/
#ifdef SIGPIPE
#endif /* SIGPIPE */
#ifdef N_FD_RESERVE
/*
* Reserve 16 low-order file descriptors for later use with stdio.
*/
# ifdef DEBUG
if (debug > 2)
printf("fdsave: ");
# endif
for (f = 0; f < N_FD_RESERVE - 1; f++) {
# ifdef DEBUG
if (debug > 2)
# endif
}
# ifdef DEBUG
if (debug > 2)
printf("\n");
# endif
#endif /* N_FD_RESERVE */
/*
* 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_mon();
init_systime();
init_timer();
init_lib();
init_random();
init_request();
init_control();
init_leap();
init_peer();
#ifdef REFCLOCK
#endif
init_proto();
init_io();
/* turn off in config if unwanted */
#ifdef N_FD_RESERVE
/* Free up low-order file descriptors for use with stdio */
# ifdef DEBUG
if (debug > 2)
printf("fdsave: closing ");
# endif
for (f = 0; f < N_FD_RESERVE - 1; f++) {
# ifdef DEBUG
if (debug > 2)
# endif
}
# ifdef DEBUG
if (debug > 2)
printf("\n");
# endif
#endif /* N_FD_RESERVE */
/*
* Get configuration. This (including argument list parsing) is
* done in a separate module since this will definitely be different
* for the gizmo board.
*/
initializing = 0;
# if defined(DEBUG)
if(!debug)
{
# endif
/*
* the service_main() thread will have to wait for requests to
* Panel or from any WIN32 application start a new thread to perform
* all the work of the NTP service
*/
0, /* stack size */
NULL))) /* argument to thread */
{
if (hServDoneEvent != NULL)
if (ResolverThreadHandle != NULL)
return;
}
/* report to the service control manager that the service is running */
{
if (hServDoneEvent != NULL)
if (ResolverThreadHandle != NULL)
return;
}
/* wait indefinitely until hServDoneEvent is signaled */
if (hServDoneEvent != NULL)
if (ResolverThreadHandle != NULL)
if (WorkerThreadHandle != NULL)
if (TimerThreadHandle != NULL)
/* restore the clock frequency back to its original value */
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
void *notUsed;
{
#endif /* defined(SYS_WINNT) && !defined(NODETACH) */
/*
* Report that we're up to any trappers
*/
/*
* 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;
for (;;)
{
#ifndef HAVE_SIGNALED_IO
extern int maxactivefd;
int nfound;
#else
#endif
if (alarm_flag) /* alarmed? */
{
was_alarmed = 1;
alarm_flag = 0;
}
{
/*
* Nothing to do. Wait for something.
*/
#ifndef HAVE_SIGNALED_IO
#if defined(VMS) || defined(SYS_VXWORKS)
/* make select() wake up after one second */
{
}
#else
#endif /* VMS */
if (nfound > 0)
{
get_systime(&ts);
(void)input_handler(&ts);
}
else if (
#ifndef SYS_WINNT
#else /* SYS_WINNT */
#endif /* SYS_WINNT */
)
else if (debug > 1)
#else /* HAVE_SIGNALED_IO */
#endif /* HAVE_SIGNALED_IO */
if (alarm_flag) /* alarmed? */
{
was_alarmed = 1;
alarm_flag = 0;
}
}
#ifdef HAVE_SIGNALED_IO
#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.
*/
{
}
/*
* Go around again
*/
}
}
#ifdef SIGDIE2
/*
* finish - exit gracefully
*/
static RETSIGTYPE
int sig;
{
#ifdef SYS_WINNT
/*
* with any exit(0)'s in the worker_thread, the service_main()
* thread needs to be informed to quit also
*/
#endif /* SYS_WINNT */
switch (sig)
{
#ifdef SIGBUS
case SIGBUS:
printf("\nfinish(SIGBUS)\n");
exit(0);
#endif
case 0: /* Should never happen... */
return;
default:
exit(0);
}
}
#endif /* SIGDIE2 */
#ifdef DEBUG
/*
* moredebug - increase debugging verbosity
*/
static RETSIGTYPE
int sig;
{
int saved_errno = errno;
if (debug < 255)
{
debug++;
}
errno = saved_errno;
}
/*
* lessdebug - decrease debugging verbosity
*/
static RETSIGTYPE
int sig;
{
int saved_errno = errno;
if (debug > 0)
{
debug--;
}
errno = saved_errno;
}
#else /* not DEBUG */
/*
* no_debug - We don't do the debug here.
*/
static RETSIGTYPE
int sig;
{
int saved_errno = errno;
errno = saved_errno;
}
#endif /* not DEBUG */
#ifdef SYS_WINNT
/* service_ctrl - control handler for NTP service
* from the control panel or other applications making
* win32API calls
*/
void
{
/* 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:
/*
* Report the status, specifying the checkpoint and waithint,
* before setting the termination event.
*/
{
}
was_stopped = 1;
return;
/* Update the service status */
break;
default:
/* invalid control code */
break;
}
{
}
}
#endif /* SYS_WINNT */