[comp.unix.xenix] NBS to system clock update

sandy@turnkey.TCC.COM (Sanford 'Sandy' Zelkovitz) (07/21/88)

The following program was uploaded to my BBS system which permits your
system to call into the National Bureau of Standards and retrieve the exact
time. It then calls /etc/setclock and updates your system clock to the
exact time for your geographic location.

To the best of my knowledge, the code is only compatible with SCO Xenix.
 
The following is the cc command line that I used to compile the code.
 
             cc -Mm2e -O nbs_time.c -lx -o nbs_time
 
I have been using the code and it works perfectly!
 
Sanford ( Sandy ) Zelkovitz
XBBS - 714-898-8634
 
           ............!ihnp4!hermix!alphacm!sandy
           ............!uunet!ccicpg!turnkey!alphacm!sandy
           ............!trwrb!ucla-an!alphacm!sandy
           ............!ucbvax!ucivax!icnvax!alphacm!sandy


--------------------------- cut here for nbs_time.c ----------------------


/* CHK=0x0603 */
/*+-----------------------------------------------------------------------
  SCO XENIX SYSTEM V.2  (Others too?)
  nbs_time.c -- call NBS, get time, hangup quickly, set system time,
  wait for top of minute, execute /etc/setclock to update cmos clock

  Warren H. Tucker, 150 West Lake Drive, Mountain Park, GA  30075
  (404)587-5766

  Note: must be root to execute

  Defined functions:
	create_lock_file(lock_file_name)
	hangup(sig)
	hayes_dial()
	hayes_send_cmd(cmd)
	lclose()
	lgetc(char_rtnd)
	lgetc_timeout(timeout_msec)
	lgets_timeout(lrwt)
	lkill_buf()
	lock_tty()
	lopen()
	lputc(lchar)
	lputs_paced(pace_msec,string)
	lrdchk()
	lset_baud_rate(ioctl_flag)
	lset_parity(ioctl_flag)
	main(argc,argv,envp)
	make_lock_name(ttyname,lock_file_name)
	other_lock_name(first_lock_name)
	to_lower(ch)
	to_upper(ch)
	ulcmpb(str1,str2)
	ulindex(str1,str2)
	unlock_tty()
	usage()
	valid_baud_rate(baud)

Sample execution:
% nbs -
nbs_time
Dialing 1(202)653-0351 ... INT to abort ... CONNECT 1200
'47361 201 020050 UTC'
Connect time 1 second(s)
Time retrieved from standard: Mon Jul 18 22:00:50 1988
Waiting for top of minute:    Mon Jul 18 22:00:51 1988
Waiting for top of minute:    Mon Jul 18 22:00:52 1988
Waiting for top of minute:    Mon Jul 18 22:00:53 1988
Waiting for top of minute:    Mon Jul 18 22:00:54 1988
Waiting for top of minute:    Mon Jul 18 22:00:55 1988
Waiting for top of minute:    Mon Jul 18 22:00:56 1988
Waiting for top of minute:    Mon Jul 18 22:00:57 1988
Waiting for top of minute:    Mon Jul 18 22:00:58 1988
/etc/setclock setting ...  result: 0618220188

------------------------------------------------------------------------*/
/*+:EDITS:*/
/*:07-18-1988-22:07-wht-working! */
/*:07-18-1988-17:27-wht-creation */

#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termio.h>

#ifndef ushort
#define ushort	unsigned short
#endif
#ifndef uchar
#define uchar	unsigned char
#endif
#ifndef uint
#define uint	unsigned int
#endif
#ifndef ulong
#define ulong	unsigned long
#endif

char  *lgets_timeout(struct lrwt  *);
char  *other_lock_name(char  *);
char to_lower(char );
char to_upper(char );
int create_lock_file(char  *);
int hayes_dial(void);
int hayes_send_cmd(char  *);
int lgetc_timeout(unsigned long );
int lock_tty(void);
int lopen(void);
int lrdchk(void);
int lset_baud_rate(int );
int main(int ,char  *  *,char  *  *);
int make_lock_name(char  *,char  *);
int ulcmpb(unsigned char  *,unsigned char  *);
int ulindex(char  *,char  *);
int valid_baud_rate(unsigned int );
void hangup(int );
void lclose(void);
void lgetc(char  *);
void lkill_buf(void);
void lputc(char );
void lputs_paced(int ,char  *);
void lset_parity(int );
void unlock_tty(void);

ushort	geteuid();
ushort	getuid();
long	nap(long);
long 	time(long *);
char	*ctime(long *);

typedef struct lrwt	/* param to lgets_timeout in eculine.c */
{
ulong	to1;		/* timeout for 1st character (granularity 20) */
ulong	to2;		/* timeout for each next char (granularity 20) */
int		raw_flag;	/* !=0, rtn full buffer, ==0, rtn filtered hayes result */
char	*buffer;	/* buffer to fill */
int		bufsize;	/* size of buffer */
int		count;		/* from proc, count rcvd */
}	LRWT;

#define	EPOCH		40587					/* UNIX starts JD 2440587, */
#define	leap(y, m)	((y+m-1 - 70%m) / m)	/* also known as 1/1/70 */
#define	TONE		'*'
/* #define	TIME		"\n%05ld %03d %02d%02d%02d UTC" */
#define	TIME		"%05ld %03d %02d%02d%02d UTC"

/* for better source line utilization, frequent use of 'fprintf' and 'stderr'
   warrants the following */
#define pf	printf
#define	ff	fprintf
#define se	stderr
#define so	stdout

/* lopen() and related routines error codes */
#define LOPEN_INVALID	-1		/* for invalid tty name */
#define LOPEN_UNKPID	-2		/* unknown pid using line */
#define LOPEN_LCKERR	-3		/* lock file open error */
#define LOPEN_NODEV		-4		/* device does not exist */
#define LOPEN_OPNFAIL	-5		/* count not open line */
#define LOPEN_ALREADY	-6		/* line already open */

extern char	*revision;		/* ecurev.c temp file from buildrev */
extern char	*numeric_revision;	/*ecunumrev.c */

char	LLCKname[128];		/* lock file name */
char	Ltelno[64];			/* telephone number for remote or null */
char	Lline[64];			/* line name */
int		Liofd;				/* file descriptor for line */
int		Lparity;			/* 0==NONE, 'e' == even, 'o' == odd */
struct termio	Llv;		/* attributes for the line to remote */
uint	Lbaud;				/* baud rate */
ushort	euid;
ushort	uid;

/*+-------------------------------------------------------------------------
    to_upper() / to_lower()
  one would think that these were relatively standard
  types of thing, but MSC/Xenix specifies toupper() to convert to upper
  case if not already and Unix says to adjust without testing,
  so, two stupid little routines here
  ASCII only -- no EBCDIC gradoo here please
--------------------------------------------------------------------------*/
char to_upper(ch)
register char    ch;
{ return( ((ch >= 'a') && (ch <= 'z')) ? ch - 0x20 : ch);
}   /* end of to_upper() */

char to_lower(ch)
register char    ch;
{ return( ((ch >= 'A') && (ch <= 'Z')) ? ch + 0x20 : ch);
}   /* end of to_lower() */

/*+----------------------------------------------------------------------------
    ulcmpb(str1,str) -- Upper/Lower [case insensitive] Compare Bytes

 Returns -1 if strings are equal, else failing character position
 If the second strings terminates with a null and both strings have matched
 character for character until that point, then -1 is returned.
 NOTE:  this is not a test for complete equality of two strings, but allows
 discovery of a string as a substring in a larger containing string.
-----------------------------------------------------------------------------*/
int
ulcmpb(str1,str2)
register unsigned char    *str1;
register unsigned char    *str2;
{
register int     istr;

    for( istr=0 ; ;  ++istr )
    {
        if(str2[istr] == '\0')          /* if second string exhausts, match! */
            return(-1);
        if((str1[istr] == '\0' ) ||
			( to_upper(str1[istr]) != to_upper(str2[istr]) ))
            return(istr);
    }
	/*NOTREACHED*/
} /* end of ulcmpb */

/*+-------------------------------------------------------------------------
    ulindex:  Upper/Lower [case insensitive] Index functioni

  Returns position of 'str2' in 'str1' if found
  If 'str2' is null, then 0 is returned (null matches anything)
  Returns -1 if not found

  uses 'ulcmpb'
--------------------------------------------------------------------------*/
int ulindex(str1,str2)
register char	*str1;	/* the (target) string to search */
register char	*str2;	/* the (comparand) string to search for */
{
register int	istr1 = 0;		/* moving index into str1 */
register char	*mstr = str1;	/* moving string pointer */

    if(str2[0] == '\0')             /* null string matches anything */
        return(0);
	while(1)
    {
        if(*mstr == '\0')           /* if we exhaust target string, flunk */
            return(-1);
        /* Can we find either case of first comparand char in target? */
        if( to_upper(*mstr) == to_upper(str2[0]) )
        {
            /* we have a first char match... does rest of string match? */
            if(ulcmpb(mstr,str2) == -1)         /* if the rest matches, ... */
                return(istr1);                  /* ... return match position */
        }
        /* we did not match this time... increment istr1, mstr and try again */
        ++istr1;
        ++mstr;
    }
}	/* end of ulindex */

/*+-----------------------------------------------------------------------
	hangup(sig) -- terminate program (with comm line cleanup)
------------------------------------------------------------------------*/
void
hangup(sig)
int		sig;
{
void	lclose();

	ff(se,"\n");
	if(Liofd != -1)
		lclose();			/* close line */
	exit(sig);
}	/* end of hangup */

/*+-------------------------------------------------------------------------
	make_lock_name(ttyname,lock_file_name)
--------------------------------------------------------------------------*/
make_lock_name(ttyname,lock_file_name)
char	*ttyname;
char	*lock_file_name;
{
register int itmp;
register char *ttyptr;

	if((itmp = ulindex(ttyname,"/dev/tty")) != 0)
		return(LOPEN_INVALID);

	itmp = ulindex(ttyname,"tty");

	ttyptr = &ttyname[itmp];
	strcpy(lock_file_name,"/usr/spool/uucp/LCK..");
	strcat(lock_file_name,ttyptr);
	return(0);

}	/* end of make_lock_name */

/*+-----------------------------------------------------------------------
	create_lock_file()

  Returns 0 if lock file created,else error codes:
	LOPEN_ if error
    else pid of process currently busy on device
------------------------------------------------------------------------*/
create_lock_file(lock_file_name)
char	*lock_file_name;
{
register int	fd_lockf;
int		pid;
int		old_umask;
int		erc = 0;

	old_umask = umask(0);

	if((fd_lockf = open(lock_file_name,O_CREAT | O_EXCL | O_RDWR,0666)) < 0)
	{		/* file already exists */
		if((fd_lockf = open(lock_file_name,O_RDWR,0666)) < 0)
		{
			erc = LOPEN_LCKERR;
			goto RESTORE_UMASK;
		}
		else if(read(fd_lockf,(char *)&pid,sizeof(pid))) 
		{
			if(kill(pid,0)) 				/* is owner pid already dead? */
			{
				if(errno == ESRCH)			/* this error sez so */
				{
					pid = getpid();			/* so we will use it */
					lseek(fd_lockf,0L,0);
					write(fd_lockf,(char *)&pid,sizeof(pid));
					close(fd_lockf);
					erc = 0;
					goto RESTORE_UMASK;
				}
			} 
			/* owner pid still active with lock */
			close(fd_lockf);
			erc = pid;			/* port is busy */
			goto RESTORE_UMASK;
		}
		else
		{
			close(fd_lockf);
			erc = LOPEN_UNKPID;
			goto RESTORE_UMASK;
		}
	} 
	pid = getpid();
	write(fd_lockf,(char *)&pid,sizeof(pid));

	close(fd_lockf);
	chmod(lock_file_name,0666);

RESTORE_UMASK:
	(void)umask(old_umask);
	return(erc);

}	/* end of create_lock_file */

/*+-------------------------------------------------------------------------
	other_lock_name(first_lock_name)
--------------------------------------------------------------------------*/
char *
other_lock_name(first_lock_name)
char	*first_lock_name;
{
register int itmp;
static char other_lock_name[64];

	strcpy(other_lock_name,first_lock_name);
	itmp = strlen(other_lock_name) - 1;
	if(islower(other_lock_name[itmp]))
		other_lock_name[itmp] = toupper(other_lock_name[itmp]);
	else if(isupper(other_lock_name[itmp]))
		other_lock_name[itmp] = tolower(other_lock_name[itmp]);

	return(other_lock_name);
		
}	/* end of other_lock_name */

/*+-------------------------------------------------------------------------
	lock_tty()
--------------------------------------------------------------------------*/
lock_tty()
{
register int itmp;
struct stat ttystat;

	if(itmp = make_lock_name(Lline,LLCKname))
		return(itmp);

	if(stat(Lline,&ttystat) < 0)
		return(LOPEN_NODEV);

	if(itmp = create_lock_file(LLCKname))
		return(itmp);

	if(itmp = create_lock_file(other_lock_name(LLCKname)))
	{
		unlink(LLCKname);
		LLCKname[0] = 0;
		return(itmp);
	}

}	/* end of lock_tty */

/*+-----------------------------------------------------------------------
	void unlock_tty()
------------------------------------------------------------------------*/
void
unlock_tty()
{

	if(LLCKname[0] == 0)
		return;

	unlink(LLCKname);
	unlink(other_lock_name(LLCKname));

	LLCKname[0] = 0;
}	/* end of unlock_tty */

/*+-------------------------------------------------------------------------
	valid_baud_rate(baud) -- returns (positive) baud rate selector
or -1 if invalid baud rate
--------------------------------------------------------------------------*/
valid_baud_rate(baud)
uint	baud;
{
	switch(baud)
	{
		case 110: return(B110);
		case 300: return(B300);
		case 600: return(B600);
		case 1200: return(B1200);
		case 2400: return(B2400);
		case 4800: return(B4800);
		case 9600: return(B9600);
		case 19200: return(EXTA);
		case 38400: return(EXTB);
		default: return(-1);
	}

}	/* end of valid_baud_rate */

/*+-----------------------------------------------------------------------
	lset_baud_rate(ioctl_flag)

  If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Llv)
  is executed after setting baud rate
------------------------------------------------------------------------*/
lset_baud_rate(ioctl_flag)
int		ioctl_flag;
{
int		baud_selector = valid_baud_rate(Lbaud);

	if(baud_selector < 0)
	{
		ff(se,"invalid baud rate: %u\n",Lbaud);
		ff(se,"valid rates: 110,300,600,1200,2400,4800,9600,19200\n");
		return(1);
	}
	Llv.c_cflag &= ~CBAUD;
	Llv.c_cflag |= baud_selector;

	if(ioctl_flag)
		 ioctl(Liofd,(int)TCSETA,(char *)&Llv);
	return(1);

}	/* end of lset_baud_rate */

/*+-----------------------------------------------------------------------
	lset_parity(ioctl_flag)

  If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Llv)
  is executed after setting parity
------------------------------------------------------------------------*/
void
lset_parity(ioctl_flag)
int		ioctl_flag;
{
	Llv.c_cflag &= ~(CS8 | PARENB | PARODD);
	switch(to_lower(Lparity))
	{
		case 'e':
			Llv.c_cflag |= CS7 | PARENB;
			Llv.c_iflag |= ISTRIP;
			break;
		case 'o':
			Llv.c_cflag |= PARODD | CS7 | PARENB;
			Llv.c_iflag |= ISTRIP;
			break;
		default:
			ff(se,"invalid parity: %c ... defaulting to no parity\n");
		case 0:
		case 'n':
			Llv.c_cflag |= CS8;
			Llv.c_iflag &= ~(ISTRIP);
			Lparity = 0;
			break;
	}			

	if(ioctl_flag)
		 ioctl(Liofd,(int)TCSETA,(char *)&Llv);

}	/* end of lset_parity */

/*+-------------------------------------------------------------------------
	lgetc(char_rtnd)
--------------------------------------------------------------------------*/
void
lgetc(char_rtnd)
char	*char_rtnd;
{

READ_AGAIN:
	errno = 0;
	if(read(Liofd,char_rtnd,1) < 1)
	{
		if(errno == EINTR)			/* if signal interrupted, ... */
			goto READ_AGAIN;
		hangup(254);
	}

}	/* end of lgetc */

/*+-------------------------------------------------------------------------
	lrdchk() -- rdchk(Liofd)
--------------------------------------------------------------------------*/
int
lrdchk()
{
	return(rdchk(Liofd));

}	/* end of lrdchk */

/*+-----------------------------------------------------------------------
	lputc(lchar) -- write lchar to comm line
------------------------------------------------------------------------*/
void
lputc(lchar)
char	lchar;
{
	while(write(Liofd,&lchar,1) != 1)
	{
		if(errno == EINTR)
			continue;
		hangup(255);
	}
}	/* end of lputc */

/*+-----------------------------------------------------------------------
	lputs_paced(pace_msec,string) -- write string to comm line
  with time between each character 
------------------------------------------------------------------------*/
void
lputs_paced(pace_msec,string)
register int pace_msec;
register char	*string;
{
register long msec = (pace_msec) ? (long)pace_msec : (long)20;

	while(*string)
	{
		lputc(*string++);
		nap(msec);
	}

}	/* end of lputs_paced */

/*+-------------------------------------------------------------------------
	char *lgets_timeout(LRWT *)

typedef struct lrwt
{
ulong	to1;
ulong	to2;
int		raw_flag;
char	*buffer;
int		bufsize;
int		count;
}	LRWT;

to1 and to2 are unsigned long values in milliseconds (not
currently supported well under BSD4); to1 is the time to wait
for the first character, to2 the time to wait for subsequent
characters.

if raw_flag 0,     non-printables are stripped from beginning
                   and end of received characters (i.e., modem
                   response reads); NULs discarded, parity stripped
if raw_flag 1,     full raw read buffer returned
if raw_flag 2,     full buffer, NULs discarded, parity stripped

buffer is address to read chars into

bufsize is buffer max size (allowing room for terminating null)
which should be at least 2 if raw_size includes 0x80 bit,
else at least 12 characters if 0x80 omitted.

count is a int which, at return, receives the actual count read

--------------------------------------------------------------------------*/
char *
lgets_timeout(lrwt)
LRWT	*lrwt;
{
register int actual_count = 0;
register char	*cptr = lrwt->buffer;
int		max_count = lrwt->bufsize;
char	*rtn_val;
int		timeout_counter;
int		qc1;
int		qc2;
long	quantum;
long	ltmp;

/* minimum wait is 60 msec */
	if(Lbaud < 300)
		if(lrwt->to2 < 300L) lrwt->to2 = 300L;
	if(Lbaud < 1200)
		if(lrwt->to2 < 200L) lrwt->to2 = 200L;
	else
		if(lrwt->to2 < 60L) lrwt->to2 = 60L;

/* shortest interval */
	ltmp = (lrwt->to1 < lrwt->to2) ? lrwt->to1 : lrwt->to2;

/* calculate wait quantum */
	quantum = ltmp / 10L;				/* try for ten ticks */
	if(quantum < 20L)
		quantum = 20L;
	qc1 = lrwt->to1 / quantum;
	if(!qc1) qc1 = 1L;
	qc2 = lrwt->to2 / quantum;
	if(!qc2) qc2 = 1L;

/* perform the lrtw function
   input: qc1 is first nap count (for first charcters) 
          qc2 is 2nd nap count (for subsequent characters) 
          quantum is the nap period in milliseconds
          cptr is char* to receive read string
          max_count is max number of characters incl null
          lrwt->raw_flag as described above

  output: lrwt->count is actual count of return result
          lrwt->buffer is return read buffer
*/
	max_count--;				/* leave room for null */

	lrwt->raw_flag &= 0x0F;		/* get rid of 0xF0 flags */
	timeout_counter = qc1;		/* first timeout */ 
	*cptr = 0;					/* init result string */
	while(timeout_counter--)
	{
		nap(quantum);
		while(lrdchk())
		{
			lgetc(cptr);
			if(lrwt->raw_flag != 1)
			{
				*cptr &= 0x7F;
				if(*cptr == 0)
					continue;
			}

			*++cptr = 0;
			actual_count++;
			if(--max_count == 0)
				goto READ_LINE_POST_PROCESS;
			timeout_counter = qc2;
		}
	}

READ_LINE_POST_PROCESS:
	if(lrwt->raw_flag)
	{
		lrwt->count = actual_count;
		return(lrwt->buffer);
	}
	cptr = lrwt->buffer;
	while(((*cptr >0) && (*cptr < 0x20)) || (*cptr >= 0x7F))
		cptr++;
	rtn_val = cptr;
	actual_count = 0;
	while(((*cptr &= 0x7F) >= 0x20) && (*cptr <= 0x7E))
	{
		cptr++;
		actual_count++;
	}
	*cptr = 0;
	strcpy(lrwt->buffer,rtn_val);
	lrwt->count = actual_count;
	return(lrwt->buffer);
}	/* end of lgets_timeout */

/*+-------------------------------------------------------------------------
	lgetc_timeout(timeout_msec)

 reads one character from line unless timeout_msec passes with no receipt.
 timeout_msec < 20 msec becomes 20 msec
 return char (raw - parity bit preserved) if received, else -1 if timeout
--------------------------------------------------------------------------*/
int
lgetc_timeout(timeout_msec)
ulong	timeout_msec;
{
LRWT	lr;
char	getc_buf[2];		/* room for one char + null */

	lr.to1 = timeout_msec;
	lr.to2 = timeout_msec;
	lr.raw_flag = 1;		/* full raw read */
	lr.buffer = getc_buf;
	lr.bufsize = sizeof(getc_buf);
	lgets_timeout(&lr);
	return(  (lr.count == 1) ? (int)getc_buf[0] : -1 );

}	/* end of lgetc_timeout */

/*+-------------------------------------------------------------------------
	lkill_buf()
--------------------------------------------------------------------------*/
void
lkill_buf()
{
	ioctl(Liofd,(int)TCFLSH,(char *)2); /* flush input and output */
}	/* end of lkill_buf */

/*+----------------------------------------------------------------------
	lopen()
returns negative LOPEN_ codes if failure else positive pid using line
else 0 if successful open
------------------------------------------------------------------------*/
int
lopen()
{
register int	itmp;

	if(Liofd >= 0)
		return(LOPEN_ALREADY);
	if(itmp = lock_tty())		/* get lock file */
		return(itmp);
	Liofd = open(Lline,O_RDWR,0777);
	if(Liofd < 0)
		return(LOPEN_OPNFAIL);
	else
	{
		ioctl(Liofd,(int)TCGETA,(char *)&Llv);
		Llv.c_iflag = (IGNPAR | IGNBRK | IXOFF );
		Llv.c_cflag |= (CREAD | HUPCL);
		Llv.c_lflag = 0;

		Llv.c_cc[VMIN]   = 1;
		Llv.c_cc[VTIME]  = 1;

		lset_baud_rate(0);		/* do not perform ioctl */
		lset_parity(1);			/* do perform ioctl */
	}

	return(0);

}	/* end of lopen */

/*+-----------------------------------------------------------------------
	lclose()
------------------------------------------------------------------------*/
void
lclose()
{
	if(Liofd < 0)
		return;
	ioctl(Liofd,(int)TCGETA,(char *)&Llv); /* save initial state */
	Llv.c_cflag |= HUPCL;
	ioctl(Liofd,(int)TCSETA,(char *)&Llv);
	close(Liofd);
	Liofd = -1;
	unlock_tty();		/* kill lock file */

}	/* end of lclose */

/*+-------------------------------------------------------------------------
	hayes_send_cmd(cmd)
  0: success (cmd accepted)
 -1: cannot talk to modem
--------------------------------------------------------------------------*/
hayes_send_cmd(cmd)
char	*cmd;
{
register char	*cptr;
int retry = 0;

	cptr = cmd;
	lkill_buf();
	while(1)
	{
		lputc(0x07);	/* something random */
		if(lgetc_timeout(500L) < 0)
		{
			if(retry)
				return(-1);
			retry = 1;
			lputs_paced(0,"ATQ0E1V1\r");
			nap((long)1500);
			lkill_buf();
			continue;
		}
		break;
	}
	while(*cptr)
	{
		lputc(*cptr++);
		if(lgetc_timeout(500L) < 0)
			return(-1);
	}
	lputc('\r');
	if(lgetc_timeout(500L) < 0)
		return(-1);
	return(0);

}	/* end of hayes_send_cmd */

/*+-----------------------------------------------------------------------
	hayes_dial()
returns 1 on success (CONNECT), 
		0 if failure to connect
		-1 if cannot talk to modem
------------------------------------------------------------------------*/
int
hayes_dial()
{
register int itmp;
char	s128[128];
int		rtn_code = -1;	/* assume fail, CONNECT will chg to zero */
int		s7;
LRWT	lr;

	s7 = 30;
	strcpy(s128,"ATV1E1S11=45DT" );
	strcat(s128,Ltelno);

	if(itmp = hayes_send_cmd(s128))
		return(itmp);

/* some modems (ahem, the Hayes 2400) do not accurately honor S7 */
	lr.to1 = s7 * 3 * 1000L;
	lr.to2 = 100L;
	lr.raw_flag = 0;
	lr.buffer = s128;
	lr.bufsize = sizeof(s128);
	ff(se,"Dialing %s ... INT to abort ... ",Ltelno);
	fflush(se);
	lgets_timeout(&lr);
	if(lr.count)
		ff(se,"%s\n",s128);
	if(strncmp(s128,"CONNECT",7) == 0)
		return(1);
	return(0);

}	/* end of hayes_dial */

/*+-------------------------------------------------------------------------
	usage()
--------------------------------------------------------------------------*/
void
usage()
{
	ff(se,"Usage: nbs_time [-][-e][-o][-n][-b#][-t#]\n");
	ff(se,"Defaults 1200-N %s %s\n",Ltelno,Lline);
	ff(se," -        use defaults\n");
	ff(se," -e       even parity\n");
	ff(se," -o       odd parity\n");
	ff(se," -n       no parity\n");
	ff(se," -b#      baud rate\n");
	ff(se," -t#      telephone number\n");
	ff(se," -l<name> line (/dev/tty??)\n");
	exit(253);

}	/* end of usage */

/*+-------------------------------------------------------------------------
	main(argc,argv,envp)

  main() program forks to create rcvr process; then main()
  becomes the xmtr process
------------------------------------------------------------------------*/
main(argc,argv,envp)
int		argc;
char	**argv;
char	**envp;
{
char	*cptr;
int		iargv;
int		swchar;
int		itmp;
LRWT	lr;
char	rd_buf[64];
long	now;
long	julian;
long	connect_time;
int		day_of_year;
int		hour;
int		min;
int		sec;
struct tm *lt;

	setbuf(stderr,NULL);
	setbuf(stdout,NULL);

	ff(se,"nbs_time\n");

/* init line variables */
	strcpy(Lline,"/dev/tty1a");
	strcpy(Ltelno,"1(202)653-0351");
	Liofd = -1;
	Lbaud = 1200;
	Lparity = 0;

	if(argc < 2)
		usage();

	if((argc == 2) && (!strcmp(argv[1],"-")))
		;
	else
	{
		for(iargv = 1; iargv < argc; iargv++)
		{
			if(*argv[iargv] != '-')
				continue;
			switch(*(argv[iargv] + 1))
			{
				case 'e': Lparity = 'e'; break;
				case 'o': Lparity = 'o'; break;
				case 'n': Lparity =  0 ; break;
				case 'b': Lbaud = atoi(argv[iargv] + 2); break;
				case 't': strcpy(Ltelno,argv[iargv] + 2); break;
				case 'l': strcpy(Lline,argv[iargv] + 2); break;
				default:  usage();
			}
		}
	}

	uid = getuid();
	euid = geteuid();
	if((euid == 0) || (uid == 0))	/* if root running or prog text ... */
		nice(-40);
	else
	{
		ff(se,"must be root\n");
		exit(252);
	}

	signal(SIGHUP,hangup);
	signal(SIGQUIT,hangup);
	signal(SIGINT,hangup);
	signal(SIGTERM,hangup);

	if(itmp = lopen())
	{
		switch(itmp)
		{
			case LOPEN_INVALID:
				ff(se,"invalid line name\n"); break;
			case LOPEN_UNKPID:
				ff(se,"unknown pid is using line\n"); break;
			case LOPEN_LCKERR:
				ff(se,"lock file error\n"); break;
			case LOPEN_NODEV:
				ff(se,"line does not exist\n"); break;
			case LOPEN_ALREADY:
				ff(se,"line already open\n"); break;
			case LOPEN_OPNFAIL:
				ff(se,"line open error\n"); break;
			default:
				ff(se,"pid %d using line\n",itmp); break;
		}
		exit(250);
	}

	if(!hayes_dial())
		hangup(1);
	connect_time = time((long *)0);

	for(itmp = 0; itmp < 30; itmp++)
	{
		if(lgetc_timeout(500L) == TONE)
			break;
	}

	lr.to1 = 1100L;
	lr.to2 =  100L;
	lr.raw_flag = 0;	/* full raw read */
	lr.buffer = rd_buf;
	lr.bufsize = sizeof(rd_buf);

	lgets_timeout(&lr);

	fputs("'",stdout);
	fwrite(lr.buffer,1,lr.count,stdout);
	fputs("'\n",stdout);

	lclose();
	fprintf(stdout,"Connect time %ld second(s)\n",
		time((long *)0) - connect_time);

	if(sscanf(lr.buffer,TIME, &julian, &day_of_year, &hour, &min, &sec) != 5)
	{
		ff(se,"garbled result: '%s'\n",lr.buffer);
		exit(240);
	}
	else
	{
		now = (((julian - EPOCH) * 24 + hour) * 60 + min) * 60 + sec;
		if(stime(&now) < 0)
			perror("stime");
		fputs("Time retrieved from standard: ",stdout);
		fputs(ctime(&now), stdout);
		lt = localtime(&now);
		while(lt->tm_sec != 58)
		{
			nap(960L);
			now = time((long *)0);
			fputs("Waiting for top of minute:    ",stdout);
			fputs(ctime(&now), stdout);
			lt = localtime(&now);
		}
		now += 60L;	/* get top of next minute */
		lt = localtime(&now);
/*                                mmddhhmmyy */
/*                                0718213488 */
		sprintf(rd_buf,"/etc/setclock %02d%02d%02d%02d%02d",
			lt->tm_mon,lt->tm_mday,lt->tm_hour,lt->tm_min,lt->tm_year);
		fputs("/etc/setclock setting ... ",stdout);
		system(rd_buf);
		fputs("result: ",stdout);
		system("/etc/setclock");
	}
	exit(0);

}	/* end of main */

/* end of nbs_time.c */

------------------------------ end of nbs_time.c ----------------------------