nbs_time
Richard Stueven
gak at gakbox.Corp.Sun.COM
Fri May 17 23:58:07 AEST 1991
Two weeks ago, I sent the attached message to the author of the
"nbs_time" program. I never received a response, so I'm going to
assume he's no loger with us, and post the message here with the hope
that nobody else encounters the problem that I had.
(NB: Like I say below, I don't know if the problem was caused by
nbs_time, a billing system error, or a telephone network error, but the
changes I made should ensure that nbs_time won't be at fault in the
future.)
have fun
gak
========================================================================
>From gak Thu May 2 10:27:59 1991
To: druhi!rafb at att.com
Subject: nbs_time
Bob,
I found your nbs_time program very useful, until I got a bill for a
$200+ phone call to the NBS number this month. Now, I don't know
whether the 1159 minute connection was due to a billing problem, a
network problem, or a bug in the code, but it prompted me to examine
the code a little more closely.
I found a couple of places that have the potential to either hang the
connection open or to go into an infinite loop under the right
circumstances. I added some code to set a 60 second alarm and to drop
the connection if the alarm expires. The updated code is attached. If
you think it's OK (I've already tested it to my own satisfaction) I
invite you to re-post it to Usenet.
If you have any questions about the changes, you can reach me at
gak at Corp.Sun.COM or attmail!gak, or on 415-336-5703.
thx
Richard Stueven
----- Begin Included Message -----
/*
* NAME: nbs_time - set system clock to National Bureau of Standards Time.
*
* WHAT:
* This program sets the system clock to the time maintained by the
* National Bureau of Standards (WWV Boulder CO).
* It assumes that the system clock is currently set to the correct
* day and year.
*/
#include <stdio.h>
#include <time.h>
#include <sys/syslocal.h>
#include <sys/rtc.h>
#include <sys/signal.h>
/* function definitions to keep lint quiet */
long time(), convert_tick(), atol();
char *getenv();
void check_tz(), log_err(), set_time(), set_rtc(), disc_nbs(), exit();
int pid; /* process id of child */
extern char *tzname[2]; /* time zone names */
#define LOG "/usr/adm/clocklog"
#define TZF "/etc/TZ"
#define SEC 60
FILE *Nbs_rd; /* file descriptor for reading from NBS */
FILE *Nbs_wt; /* file descriptor for writing to NBS */
char Mon_size[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
#define LEAP_YR(yr) ((((yr) % 4) == 0) && (((yr) % 400) != 0))
main()
{
int timed_out(); /* Alarm handler */
(void)signal(SIGALRM, timed_out);
/* Start log for this run */
(void)freopen(LOG, "a", stdout);
setbuf(stdout, NULL); /* unbuffered output to log */
check_tz();
if(call_nbs() < 0) /* Call the National Bureau of Standards */
{
exit(1);
}
set_time(); /* Set the system clock on this machine. */
disc_nbs(); /* Disconnect the call to NBS */
return(0);
}
int call_nbs()
{
int p1[2]; /* pipe from cu process */
int p2[2]; /* pipe to cu process */
if(pipe(p1) < 0 || pipe(p2) < 0) /* create the pipes */
{
log_err(0L, "Cannot create pipes.\n", 0, 0);
return(-1); /* pipe create failed */
}
(void)setpgrp(); /* Set process group ID, just in case */
/* something happens and we have to */
/* terminate after the fork() */
if((pid = fork()) < 0)
{
log_err(0L, "Cannot fork for child process.\n", 0, 0);
return(-1); /* fork failed */
}
if(pid != 0) /* parent process */
{
(void)close(p1[1]); /* close the unused end of pipe 1 */
(void)close(p2[0]); /* close the unused end of pipe 2 */
Nbs_rd = fdopen(p1[0], "r"); /* save the pipe end for NBS read */
Nbs_wt = fdopen(p2[1], "w"); /* save the pipe end for NBS write */
setbuf(Nbs_rd, NULL); /* set unbuffered mode */
setbuf(Nbs_wt, NULL); /* set unbuffered mode */
return(0);
}
/* this is the child process - set up stdin, stdout, stderr and exec cu */
(void)close(p1[0]); /* close the unused end of pipe 1 */
(void)close(p2[1]); /* close the unused end of pipe 2 */
(void)close(0); (void)dup(p2[0]); /* set up pipe 2 as stdin */
(void)close(1); (void)dup(p1[1]); /* set up pipe 1 as stdout */
(void)close(2); (void)dup(p1[1]); /* set up pipe 1 as stderr */
(void)execl("/usr/bin/cu", "cu", "-s1200", NBS_PH, 0);
return(-1);
}
void disc_nbs()
{
(void)fprintf(Nbs_wt, "~.\n"); /* write the cu disconnect command */
return;
}
/*
* The NSB output includes some header information (several lines) followed
* followed by a clock tick every second. The clock tick contains all of
* the information needed to set the unix clock. The additional fields are
* ignored.
*
* 00000000001111111111222222222233333333334444444444
* 01234567890123456789012345678901234567890123456789
* jdate yr-mo-dd hh:mm:ss ds l cor msadv tz v
*
* 47588 89-03-03 20:33:45 81 0 -.2 045.0 UTC(NIST) *
*/
void set_time()
{
long new_time; /* the converted time */
long cur_time; /* current system time */
short got_tick; /* how many ticks seen? */
char buf[80]; /* buffer for NSB tick data */
long delta; /* time delta */
char *dir; /* is clock slow or fast */
int rc; /* return code from stime() */
unsigned alarm();
(void)alarm((unsigned)SEC);
got_tick = 0; /* don't have one yet */
while(fgets(buf, 80, Nbs_rd) != NULL)
{
if(strncmp(&buf[39], "UTC", 3) == 0)
{
if(++got_tick >= 3)
{
break; /* take the third valid tick to insure sync */
}
}
}
(void)alarm((unsigned)0);
if(got_tick == 0)
{
/* print last cu error line */
log_err(0L, "%s", buf, 0);
return;
}
/* got a tick, so convert it to seconds since 1/1/70 00:00:00 GMT */
new_time = convert_tick(buf);
/* now re-sync with the source */
(void)alarm((unsigned)SEC);
got_tick = 0; /* don't have a tick yet */
while(fgets(buf, 80, Nbs_rd) != NULL)
{
if(strncmp(&buf[39], "UTC", 3) == 0)
{
new_time++; /* add a second for each tick we read */
if(++got_tick >= 3)
{
break; /* take the third valid tick to insure sync */
}
}
}
(void)alarm((unsigned)0);
(void)time(&cur_time); /* get current time */
rc = stime(&new_time); /* set the time */
delta = new_time - cur_time; /* get delta */
if(delta != 0L)
{
dir = "slow";
if(delta < 0L)
{
dir = "fast";
delta = -delta;
}
log_err(cur_time, "Clock is %ld seconds %s.", delta, dir);
if(rc < 0)
{
log_err(cur_time, "Clock not set; permission denied.\n", 0, 0);
}
else
{
log_err(new_time, "New time set.\n", 0, 0);
}
}
else
{
log_err(0L, "Clock is correct.\n", 0, 0);
}
set_rtc(); /* sync the hardware clock */
return;
}
long convert_tick(buf)
char *buf;
{
short i; /* generic loop variable */
short year; /* current year from tick */
short mon; /* current month from tick */
long new_time; /* the converted time */
/* convert tick to seconds since 1/1/70 00:00:00 GMT */
new_time = 0L;
/* add on years, new_time contains days */
year = 1900 + atoi(buf + 6);
for(i = 1970; i < year; i++)
{
new_time = new_time + 365L;
if(LEAP_YR(i))
{
new_time = new_time + 1L; /* add the leap day */
}
}
/* add on months this year, new_time in days */
mon = atoi(buf + 9) - 1;
for(i = 0; i < mon; i++)
{
new_time = new_time + (long)Mon_size[i];
}
if(mon > 1 && LEAP_YR(year))
{
new_time = new_time + 1L; /* add the leap day */
}
/* add on days this month, convert new_time to hours */
new_time = (new_time + (atol(buf + 12) - 1)) * 24L;
/* add hours this day, convert new_time to minutes */
new_time = (new_time + atol(buf + 15)) * 60L;
/* add minutes this hour, convert new_time to seconds */
new_time = (new_time + atol(buf + 18)) * 60L;
/* add seconds this minute */
new_time = new_time + atol(buf + 21);
return(new_time);
}
void set_rtc()
{
long cur_time; /* current time on software clock */
struct rtc rtc; /* structure for setting real time clock */
struct tm *tm; /* pointer to localtime() structure */
/* now set the hardware clock */
(void)time(&cur_time);
tm = localtime(&cur_time); /* convert time to local time */
rtc.wkday = tm->tm_wday;
rtc.yr10 = tm->tm_year / 10;
rtc.yr1 = tm->tm_year % 10;
rtc.mon10 = (tm->tm_mon + 1) / 10;
rtc.mon1 = (tm->tm_mon + 1) % 10;
rtc.day10 = tm->tm_mday / 10;
rtc.day1 = tm->tm_mday % 10;
rtc.hr10 = tm->tm_hour / 10;
rtc.hr1 = tm->tm_hour % 10;
rtc.min10 = tm->tm_min / 10;
rtc.min1 = tm->tm_min % 10;
rtc.sec10 = tm->tm_sec / 10;
rtc.sec1 = tm->tm_sec % 10;
(void)syslocal(SYSL_WRTRTC, &rtc); /* write to RTC */
return;
}
/* VARARGS2 */
void log_err(tim, fmt, arg1, arg2)
long tim; /* time for time stamp (0 means current time) */
char *fmt; /* printf style format argument */
int arg1; /* first printf argument */
int arg2; /* second printf argument */
{
struct tm *tm; /* pointer to local time structure */
if(tim == 0L)
{
(void)time(&tim); /* get current time */
}
tm = localtime(&tim); /* convert tim to local time */
/* generate time stamp */
(void)printf("%.2d/%.2d/%.2d", tm->tm_mon + 1, tm->tm_mday, tm->tm_year);
(void)printf("-%.2d:%.2d:%.2d ", tm->tm_hour, tm->tm_min, tm->tm_sec);
(void)printf(fmt, arg1, arg2);
(void)printf("\n");
return;
}
void check_tz()
{
char *p; /* pointer for TZ string */
if((p = getenv("TZ")) == NULL)
{
if(freopen(TZF, "r", stdin) != NULL)
{
p = "TZ= "; /* enough space for TZ=XST-nnXDT */
if(gets(p+3) != NULL)
{
if(putenv(p) == 0)
{
log_err(0L, "Set %s.", p, 0);
return;
}
}
}
log_err(0L, "Using Default TZ (%s).", tzname[0], 0);
}
return;
}
int timed_out()
{
log_err(0L, "Timed out.\n", 0, 0);
(void)kill(0, SIGTERM);
exit(2);
}
----- End Included Message -----
---------------------------------------------------------------------------
--
I guess there's some things | Seems like the more I think I know
I'm not meant to understand | The more I find I don't
Ain't life a riot? Ain't love grand? | Every answer opens up so many questions
Richard Stueven gak at Corp.Sun.COM ...!attmail!gak
More information about the Comp.sys.3b1
mailing list