[alt.sources] N.B.S. clock update program

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

The following is a program which was uploaded to my BBS which causes your
computer to call the National Bureau of Standards and retrieve the exact
time. It then calls /etc/setclock and updates your system clock. Please
note that this program, to the best of my knowledge, only runs under
SCO Xenix.
 
Sanford ( Sandy ) Zelkovitz
XBBS - 714-898-8634
 
P.S. The way that I compiled the code, under Xenix286, is as follows:

cc -Mm2e -O nbs_time.c -lx -o nbs_time

----------------------- 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 */