home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Set UNIX system clock from the atomic clock at the National
- Institute of Standards and Technology (NIST) in Boulder Colorado.
-
- Designed and implemented in May of 1991 by John Walker.
-
- This program, which should be run when in super-user mode, dials
- into the telephone time service maintained by the NIST in Boulder,
- obtains the time from the atomic clock there (obtaining two
- consecutive valid readings to guard against communication errors),
- then sets the system clock at the moment the time hack is received
- for the next second. While waiting for the tick, the program goes
- into a high-priority CPU loop waiting for the tick to be received
- to obtain the best accuracy.
-
- The modem port, modem dial codes and telephone number, and various
- other parameters are set on the command line. The defaults are
- equivalent to the following:
-
- settime
- -M/dev/cua0 -- Modem port
- -NATDT13034944774 -- Dial command and phone number
- -T120 -- Two minute timeout
-
- If you specify the "-E" option, all modem input and output will be
- echoed to standard output.
-
- You don't have to be super-user to run the progrmam, but if you
- aren't the system time and date won't be changed, as only the
- super-user may change them.
-
- */
-
- #define REVDATE "13th May 1991"
-
- #include <sys/types.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <termio.h>
- #include <time.h>
-
- #define FALSE 0
- #define TRUE 1
-
- #define EOS '\0'
-
- struct termio newmode, oldmode;
-
- static char *modem = "/dev/cua0"; /* Modem file name */
- static char *dialstring = "ATDT13034944774"; /* Dial command */
- static int echoin = FALSE; /* Echo modem info if nonzero */
- static int port; /* Modem file descriptor */
- static char line[132]; /* Input buffer */
- static int jdate1970 = 2440588; /* Julian date of January 1, 1970 */
- static long usdelay; /* Line delay in microseconds */
- static time_t bailout; /* Time to give up if no success */
-
- /* TIMEDOUT -- Check for timeout expired. */
-
- static int timedout()
- {
- return time(NULL) > bailout;
- }
-
- /* MREAD -- Read next character from modem. */
-
- static int mread(buf)
- char *buf;
- {
- return read(port, buf, 1);
- }
-
-
- /* INLINE -- Obtain a newline terminated input line from the modem. */
-
- static int inline()
- {
- int l = 0;
- char buf;
-
- while (TRUE) {
- if (mread(&buf) > 0) {
- if (echoin) {
- putchar(buf);
- }
- if (buf == '\n') {
- line[l] = EOS;
- break;
- }
- if (buf >= ' ' && l < 131) {
- line[l++] = buf;
- }
- } else {
- if (timedout()) {
- strcpy(line, "BUSY");
- return FALSE;
- }
- usleep(4000L);
- }
- }
- return TRUE;
- }
-
- /* JDATE -- Convert internal GMT date and time to Julian day
- and fraction. */
-
- static long jdate(t)
- struct tm *t;
- {
- long c, m, y;
-
- y = t->tm_year + 1900;
- m = t->tm_mon + 1;
- if (m > 2)
- m = m - 3;
- else {
- m = m + 9;
- y--;
- }
- c = y / 100L; /* Compute century */
- y -= 100L * c;
- return t->tm_mday + (c * 146097L) / 4 + (y * 1461L) / 4 +
- (m * 153L + 2) / 5 + 1721119L;
- }
-
- /* PARSE_NIST -- Parse NIST time string into a "tm" structure. */
-
- static int parse_nist()
- {
- int jd, yr, mo, da, hh, mm, ss, dst, ls, msadvw, msadvf;
- char dut1[3], tname[20];
- time_t gt;
- struct tm t;
-
- if (sscanf(line, "%5d %2d-%2d-%2d %2d:%2d:%2d %2d %1d %3c %3d.%1d %s",
- &jd, &yr, &mo, &da, &hh, &mm, &ss, &dst, &ls, dut1, &msadvw,
- &msadvf, tname) < 13)
- return 0;
-
- if (strncmp(tname, "UTC(NIST)", 9) != 0)
- return 0;
-
- t.tm_sec = ss;
- t.tm_min = mm;
- t.tm_hour = hh;
- t.tm_mday = da;
- t.tm_mon = mo - 1;
- t.tm_year = (yr > 90) ? yr : (yr + 100);
- t.tm_isdst = (dst > 0) && (dst <= 50);
- t.tm_wday = ((jd + 3) % 7);
-
- usdelay = ((msadvw * 10) + msadvf) * 100;
-
- gt = ((((jdate(&t) - jdate1970) * 24 + t.tm_hour) * 60) +
- t.tm_min) * 60 + t.tm_sec;
-
- #ifdef DEBUG
- { char *cp = asctime(gmtime(>));
- printf("Clock %d (%d) Date and time: %s Delay = %d\n", gt, time(NULL), cp,
- usdelay);
- }
- #endif
- return gt;
- }
-
- int main(argc, argv)
- int argc; char *argv[];
- {
- int i, success;
- char *cp, opt;
- time_t ptime, ntime;
- struct timeval tv;
- int timeout = 120; /* How long to attempt to get time */
-
- #ifdef TEST1
- strcpy(line, "48388 91-05-12 20:48:58 50 0 +.3 045.0 UTC(NIST) *");
- parse_nist(&ntime);
- return 0;
- #endif
-
- for (i = 1; i < argc; i++) {
- cp = argv[i];
- if (*cp == '-') {
- opt = *(++cp);
- if (islower(opt))
- opt = toupper(opt);
- switch (opt) {
-
- case 'E':
- echoin = TRUE;
- break;
-
- case 'M':
- modem = cp + 1;
- break;
-
- case 'N':
- dialstring = cp + 1;
- break;
-
- case 'T':
- timeout = atoi(cp + 1);
- break;
-
- case '?':
- case 'U':
- fprintf(stderr,"\nSETTIME -- Set time from NIST time service. Call");
- fprintf(stderr,
- "\n with settime [options]");
- fprintf(stderr,"\n");
- fprintf(stderr,"\n Options:");
- fprintf(stderr,"\n -E Echo modem input and output");
- fprintf(stderr,"\n -Mdev Use modem device dev");
- fprintf(stderr,"\n -Ncmd Use cmd as modem dial command");
- fprintf(stderr,"\n -Tn Set timeout to n seconds");
- fprintf(stderr,"\n");
- fprintf(stderr,"\n (P) Throoput Ltd. %s", REVDATE);
- fprintf(stderr,"\n All Rights Reversed");
- fprintf(stderr,"\n");
- return 0;
- }
- } else {
- }
- }
-
- if ((port = open(modem, O_RDWR | O_NDELAY)) == -1) {
- fprintf(stderr, "Cannot open modem port %s\n", modem);
- return 2;
- }
- if (ioctl(port, TCGETA, &oldmode) == -1) { /* Get current tty mode */
- perror(modem);
- return 2;
- }
- newmode = oldmode; /* Save it to restore port later */
- bailout = time(NULL) + timeout; /* Set time to give up */
-
- if (echoin) {
- setbuf(stdout, NULL); /* Make echoed output unbuffered */
- }
-
- /* Set the modem port to the proper modes for calling the time
- service. */
-
- newmode.c_iflag = IGNBRK | IGNPAR | ISTRIP;
- newmode.c_oflag = 0;
- newmode.c_cflag = B1200 | CS7 | CREAD | PARENB | HUPCL;
- newmode.c_lflag = 0;
- if (ioctl(port, TCSETA, &newmode) == -1) {
- fprintf(stderr, "Cannot set modem to desired modes\n");
- perror(modem);
- return 2;
- }
-
- /* Dial the time service. */
-
- if (fcntl(port, F_SETFL, FNDELAY) == -1) {
- fprintf(stderr, "Cannot set port to non-delayed response\n");
- perror(modem);
- return 2;
- }
- if (write(port, "\r\r\r", 3) != 3) {
- fprintf(stderr, "Error sending CR's to modem\n");
- perror(modem);
- return 2;
- }
- sleep(1);
- while (read(port, &opt, 1) > 0) ; /* Flush input */
- if (echoin) {
- printf("%s\n", dialstring);
- }
- if (write(port, dialstring, strlen(dialstring)) != strlen(dialstring) ||
- write(port, "\r", 1) != 1) {
- fprintf(stderr, "Error sending dial string to modem\n");
- perror(modem);
- }
-
- /* Wait until we're connected. If we get a busy signal, give up
- and report an error status. */
-
- while (inline()) {
- if ((strncmp(line, "CONNECT", 7) == 0) || (line[0] == '5')) {
- break;
- }
- if (strncmp(line, "BUSY", 4) == 0 ||
- strncmp(line, "NO ", 3) == 0 ||
- strncmp(line, "ERROR", 5) == 0 ||
- line[0] == '3' || line[0] == '4' || line[0] == '6' ||
- line[0] == '7' || line[0] == '8') {
- fprintf(stderr, "Unable to connect.\n");
- return 1;
- }
- }
-
- /* At this point we're connected. Ignore all data from the line
- until we receive two consecutive valid time signals one second
- apart. Once we've received these two signals, prepare the
- time setting for the next second and spin until we receive
- the "*" that indicates the correct instant to set the clock.
- At that moment, change the system clock. */
-
- ptime = 0;
- success = FALSE;
- while (!success && !timedout() && inline()) {
- if (ptime == 0) {
- ptime = parse_nist();
- ntime = 0;
- } else if (ntime == 0) {
- ntime = parse_nist();
- if (ntime == (ptime + 1)) {
- int rpyet = 0;
-
- tv.tv_sec = ntime + 1;
- tv.tv_usec = 0;
- while (TRUE) {
- char buf;
- int ticker = 0; /* CPU loop timeout check */
-
- if (mread(&buf) > 0) {
- if (echoin) {
- putchar(buf);
- }
- if ((buf == '*') || (buf == '#')) {
- settimeofday(&tv, NULL);
- success = TRUE;
- nice(10); /* Drop to normal priority */
- break;
- } else if (buf == ')') {
- rpyet = 1;
- nice(-10); /* Set high priority */
- } else if (buf < ' ') {
- ptime = 0;
- if (rpyet) {
- nice(10); /* Drop to normal priority */
- }
- }
- } else {
- if (!rpyet) {
- usleep(2000L);
- if (timedout()) {
- break;
- }
- } else {
- if (((++ticker) % 100) == 0) {
- if (timedout()) {
- break;
- }
- }
- }
- }
- }
- } else {
- ptime = 0;
- }
- }
- }
-
- if (echoin) {
- putchar('\n');
- }
- if (success) {
- printf("Universal time: %s", asctime(gmtime(&tv.tv_sec)));
- printf("Local time: %s", asctime(localtime(&tv.tv_sec)));
- }
-
- /* Restore port to original modes and close, disconnecting the
- modem. */
-
- ioctl(port, TCSETAW, &oldmode);
- ioctl(port, TCFLSH, 2);
- close(port);
-
- return 0;
- }
-