📄 ntptimeset.c
字号:
/* * ntptimeset - get/set the time via ntp * * GOAL: * The goal of ntptime is to set the current time on system startup * to the best possible time using the network very wisely. It is assumed * that after a resonable time has been sett then ntp daemon will * maintain it. * * PROBLEM DOMAIN: * We have three sets of issues related to acheiving the goal. The first * issue is using the network when normal traffic is happening or when * the entire network world is recovering from a campus wide power failure * and is restarting. The second issue is the class of machine whether it * is a user's office workstation being handled by an uneducated user or * a server computer being handled by a trained operations staff. The third * issue is whether the ratio of people to computers and whether the * environment is stable and viable or not. * * NETWORK USAGE: * The first issue of using the network wisely is a question of whether * the network load and time server load and state are normal. If things * are normal ntptime can do what ntpdate does of sending out 4 packets * quickly to each server (new transmit done with each ack). However * if network or time load is high then this scheme will simply contribute * to problems. Given we have minimal state, we simply weight lost packets * significantly and make sure we throttle output as much as possible * without performance lost for quick startups. * * TRAINING AND KNOWLEDGE: * The second issue of uneducated user of a office workstation versus a * trained operation staff of a server machine translates into simply an * issue of untrained and trained users. * * The training issue implies that for the sake of the users involved in the * handling of their office workstation, problems and options should be * communicated simply and effectively and not in terse expert related * descriptions without possible options to be taken. The operator's training * and education enables them to deal with either type of communication and * control. * * AUTOMATION AND MANUAL CONTROL: * The last issue boils down to a design problem. If the design tends to go * into a manual mode when the environment is non-viable then one person * handling many computers all at the same time will be heavily impacted. On * the other hand, if the design tends to be automatic and does not indicate * a way for the user to take over control then the computer will be * unavailable for the user until the proble is resolved by someone else or * the user. * * NOTE: Please do not have this program print out every minute some line, * of output. If this happens and the environment is in trouble then * many pages of paper on many different machines will be filled up. * Save some tress in your lifetime. * * CONCLUSION: * The behavior of the program derived from these three issues should be * that during normal situations it quickly sets the time and allow the * system to startup. * * However during abnormal conditions as detected by unresponsive servers, * out-of-sync or bad responses and other detections, it should print out * a simple but clear message and continue in a mellow way to get the best * possible time. It may never get the time and if so should also indicate * this. * * Rudy Nedved * 18-May-1993 * **************************************************************** * * Much of the above is confusing or no longer relevant. For example, * it is rare these days for a machine's console to be a printing terminal, * so the comment about saving trees doesn't mean much. Nonetheless, * the basic principles still stand: * * - Work automatically, without human control or intervention. To * this end, we use the same configuration file as ntpd itself, so * you don't have to specify servers or other information on the * command line. We also recognize that sometimes we won't be able * to contact any servers, and give up in that event instead of * hanging forever. * * - Behave in a sane way, both internally and externally, even in the * face of insane conditions. That means we back off quickly when * we don't hear a response, to avoid network congestion. Like * ntpd, we verify responses from several servers before accepting * the new time data. * * However, we don't assume that the local clock is right, or even * close, because it might not be at boot time, and we want to catch * and correct that situation. This behaviour has saved us in several * instances. On HP-UX 9.0x, there used to be a bug in adjtimed which * would cause the time to be set to some wild value, making the machine * essentially unusable (we use Kerberos authentication pervasively, * and it requires workstations and servers to have a time within five * minutes of the Kerberos server). We also have problems on PC's * running both Linux and some Microsoft OS -- they tend to disagree * on what the BIOS clock should say, and who should update it, and * when. On those systems, we not only run ntptimeset at boot, we * also reset the BIOS clock based on the result, so the correct * time will be retained across reboots. * * For these reasons, and others, we have continued to use this tool * rather than ntpdate. It is run automatically at boot time on every * workstation and server in our facility. * * In the past, we called this program 'ntptime'. Unfortunately, the * ntp v4 distribution also includes a program with that name. In * order to avoid confusion, we have renamed our program 'ntptimeset', * which more accurately describes what it does. * * Jeffrey T. Hutzelman (N3NHS) <jhutz+@cmu.edu> * School of Computer Science - Research Computing Facility * Carnegie Mellon University - Pittsburgh, PA * 16-Aug-1999 * */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include "ntp_machine.h"#include "ntp_fp.h"#include "ntp.h"#include "ntp_io.h"#include "iosignal.h"#include "ntp_unixtime.h"#include "ntpdate.h"#include "ntp_string.h"#include "ntp_syslog.h"#include "ntp_select.h"#include "ntp_stdlib.h"#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <stdio.h>#include <signal.h>#include <ctype.h>#ifndef SYS_WINNT# ifdef HAVE_SYS_SIGNAL_H# include <sys/signal.h># else# include <signal.h># endif# include <sys/ioctl.h>#endif /* SYS_WINNT */#ifdef HAVE_SYS_RESOURCE_H# include <sys/resource.h>#endif /* HAVE_SYS_RESOURCE_H */#ifdef SYS_VXWORKS# include "ioLib.h"# include "sockLib.h"# include "timers.h"#endif#include "recvbuff.h"#ifdef SYS_WINNT# define TARGET_RESOLUTION 1 /* Try for 1-millisecond accuracy on Windows NT timers. */#pragma comment(lib, "winmm")#endif /* SYS_WINNT *//* * Scheduling priority we run at */#ifndef SYS_VXWORKS# define NTPDATE_PRIO (-12)#else# define NTPDATE_PRIO (100)#endif#if defined(HAVE_TIMER_SETTIME) || defined (HAVE_TIMER_CREATE)/* POSIX TIMERS - vxWorks doesn't have itimer - casey */static timer_t ntpdate_timerid;#endif/* * Compatibility stuff for Version 2 */#define NTP_MAXSKW 0x28f /* 0.01 sec in fp format */#define NTP_MINDIST 0x51f /* 0.02 sec in fp format */#define NTP_INFIN 15 /* max stratum, infinity a la Bellman-Ford */#define NTP_MAXWGT (8*FP_SECOND) /* maximum select weight 8 seconds */#define NTP_MAXLIST 5 /* maximum select list size */#define PEER_SHIFT 8 /* 8 suitable for crystal time base *//* * Debugging flag */volatile int debug = 0;/* * File descriptor masks etc. for call to select */int fd;fd_set fdmask;/* * Initializing flag. All async routines watch this and only do their * thing when it is clear. */int initializing = 1;/* * Alarm flag. Set when an alarm occurs */volatile int alarm_flag = 0;/* * Set the time if valid time determined */int set_time = 0;/* * transmission rate control */#define MINTRANSMITS (3) /* minimum total packets per server */#define MAXXMITCOUNT (2) /* maximum packets per time interrupt *//* * time setting constraints */#define DESIREDDISP (4*FP_SECOND) /* desired dispersion, (fp 4) */int max_period = DEFMAXPERIOD;int min_servers = DEFMINSERVERS;int min_valid = DEFMINVALID;/* * counters related to time setting constraints */int contacted = 0; /* # of servers we have sent to */int responding = 0; /* servers responding */int validcount = 0; /* servers with valid time */int valid_n_low = 0; /* valid time servers with low dispersion *//* * Unpriviledged port flag. */int unpriv_port = 0;/* * Program name. */char *progname;/* * Systemwide parameters and flags */struct server **sys_servers; /* the server list */int sys_numservers = 0; /* number of servers to poll */int sys_authenticate = 0; /* true when authenticating */u_int32 sys_authkey = 0; /* set to authentication key in use */u_long sys_authdelay = 0; /* authentication delay *//* * The current internal time */u_long current_time = 0;/* * File of encryption keys */#ifndef KEYFILE# ifndef SYS_WINNT#define KEYFILE "/etc/ntp.keys"# else#define KEYFILE "%windir%\\ntp.keys"# endif /* SYS_WINNT */#endif /* KEYFILE */#ifndef SYS_WINNTconst char *key_file = KEYFILE;#elsechar key_file_storage[MAX_PATH+1], *key_file ;#endif /* SYS_WINNT *//* * total packet counts */u_long total_xmit = 0;u_long total_recv = 0;/* * Miscellaneous flags */int verbose = 0;#define HORRIBLEOK 3 /* how many packets to let out */int horrible = 0; /* how many packets we drop for testing */int secondhalf = 0; /* second half of timeout period */int printmsg = 0; /* print time response analysis *//* * The half time and finish time in internal time */u_long half_time = 0;u_long finish_time = 0;int ntptimesetmain P((int argc, char *argv[]));static void analysis P((int final));static int have_enough P((void));static void transmit P((register struct server *server));static void receive P((struct recvbuf *rbufp));static void clock_filter P((register struct server *server, s_fp d, l_fp *c));static void clock_count P((void));static struct server *clock_select P((void));static void set_local_clock P((void));static struct server *findserver P((struct sockaddr_in *addr));static void timer P((void));#ifndef SYS_WINNTstatic RETSIGTYPE alarming P((int sig));#endif /* SYS_WINNT */static void init_alarm P((void));static void init_io P((void));static int sendpkt P((struct sockaddr_in *dest, struct pkt *pkt, int len)); void input_handler P((l_fp *xts));static void printserver P((register struct server *pp, FILE *fp));#if !defined(HAVE_VSPRINTF)int vsprintf P((char *str, const char *fmt, va_list ap));#endif#ifdef HAVE_SIGNALED_IOextern void wait_for_signal P((void));extern void unblock_io_and_alarm P((void));extern void block_io_and_alarm P((void));#endif#ifdef NO_MAIN_ALLOWEDCALL(ntptimeset,"ntptimeset",ntptimesetmain);void clear_globals(){ /* * Debugging flag */ debug = 0; ntp_optind = 0; /* * Initializing flag. All async routines watch this and only do their * thing when it is clear. */ initializing = 1; /* * Alarm flag. Set when an alarm occurs */ alarm_flag = 0; /* * Unpriviledged port flag. */ unpriv_port = 0; /* * Systemwide parameters and flags */ sys_numservers = 0; /* number of servers to poll */ sys_authenticate = 0; /* true when authenticating */ sys_authkey = 0; /* set to authentication key in use */ sys_authdelay = 0; /* authentication delay */ /* * The current internal time */ current_time = 0; verbose = 0;}#endif /* NO_MAIN_ALLOWED *//* * Main program. Initialize us and loop waiting for I/O and/or * timer expiries. */#ifndef NO_MAIN_ALLOWEDintmain( int argc, char *argv[] ){ return ntptimesetmain(argc, argv);}#endif /* NO_MAIN_ALLOWED */ intntptimesetmain( int argc, char *argv[] ){ int was_alarmed; struct recvbuf *rbuflist; struct recvbuf *rbuf; l_fp tmp; int errflg; int c; extern char *ntp_optarg; extern int ntp_optind; int ltmp; char *cfgpath;#ifdef SYS_WINNT HANDLE process_handle; wVersionRequested = MAKEWORD(1,1); if (WSAStartup(wVersionRequested, &wsaData)) { msyslog(LOG_ERR, "No useable winsock.dll: %m"); exit(1); }#endif /* SYS_WINNT */#ifdef NO_MAIN_ALLOWED clear_globals();#endif errflg = 0; cfgpath = 0; progname = argv[0]; syslogit = 0; /* * Decode argument list */ while ((c = ntp_getopt(argc, argv, "a:c:de:slt:uvHS:V:")) != EOF) switch (c) { case 'a': c = atoi(ntp_optarg); sys_authenticate = 1; sys_authkey = c; break; case 'c': cfgpath = ntp_optarg; break; case 'd': ++debug; break; case 'e': if (!atolfp(ntp_optarg, &tmp) || tmp.l_ui != 0) { (void) fprintf(stderr, "%s: encryption delay %s is unlikely\n", progname, ntp_optarg); errflg++; } else { sys_authdelay = tmp.l_uf; } break; case 's': set_time = 1; break; case 'l': syslogit = 1; break; case 't': ltmp = atoi(ntp_optarg); if (ltmp <= 0) { (void) fprintf(stderr, "%s: maximum time period (%d) is invalid\n", progname, ltmp); errflg++; } else max_period = ltmp; break; case 'u': unpriv_port = 1; break; case 'v': ++verbose; break; case 'H': horrible++; break; case 'S': ltmp = atoi(ntp_optarg); if (ltmp <= 0) { (void) fprintf(stderr, "%s: minimum responding (%d) is invalid\n", progname, ltmp); errflg++; } else min_servers = ltmp; break; case 'V': ltmp = atoi(ntp_optarg); if (ltmp <= 0) { (void) fprintf(stderr, "%s: minimum valid (%d) is invalid\n", progname, ltmp); errflg++; } else min_valid = ltmp; break; case '?': ++errflg; break; default: break; } if (errflg || ntp_optind < argc) { fprintf(stderr,"usage: %s [switches...]\n",progname); fprintf(stderr," -v (verbose)\n"); fprintf(stderr," -c path (set config file path)\n"); fprintf(stderr," -a key (authenticate using key)\n"); fprintf(stderr," -e delay (authentication delay)\n"); fprintf(stderr," -S num (# of servers that must respond)\n"); fprintf(stderr," -V num (# of servers that must valid)\n"); fprintf(stderr," -s (set the time based if okay)\n"); fprintf(stderr," -t secs (time period before ending)\n"); fprintf(stderr," -l (use syslog facility)\n"); fprintf(stderr," -u (use unprivileged port)\n"); fprintf(stderr," -H (drop packets for debugging)\n"); fprintf(stderr," -d (debug output)\n"); exit(2); } /* * Logging. Open the syslog if we have to */ if (syslogit) {#if !defined (SYS_WINNT) && !defined (SYS_VXWORKS) && !defined SYS_CYGWIN32# ifndef LOG_DAEMON openlog("ntptimeset", LOG_PID);# else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -