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