[alt.sources] cmostime3 part 01/02

wht@n4hgf.Mt-Park.GA.US (Warren Tucker) (12/29/90)

As it went out to comp.sources.misc a while back,
the much nicer cmostime; replaces nbs_time, which had a life of six days,
but doesn't seem to want to die :-)

Two parts.

---- Cut Here and unpack ----
#!/bin/sh
# This is cmostime3, a shell archive (shar 3.04)
# made 01/17/1990 06:14 UTC by gatech!kd4nc!n4hgf!wht (wht%n4hgf@gatech.edu)
# Source directory /u1/src/cmos
#
# existing files WILL be overwritten
#
# This is part 1 of a multipart archive                                    
# do not concatenate these parts, unpack them in order with /bin/sh        
#
# This shar contains:
#    MANIFEST
#    README
#    Makefile
#    CMOSstime.c
#    NBSsetclk.c
#    at_cmos.h
#    cmos_disp.c
#    dev_cmos.c
#    dev_cmos.h
#    set_24hr.c
#
touch 2>&1 | fgrep '[-amc]' > /tmp/s3_touch$$
if [ -s /tmp/s3_touch$$ ]
then
	TOUCH=can
else
	TOUCH=cannot
fi
rm -f /tmp/s3_touch$$
if test -r s3_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s3_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting MANIFEST (Text)"
sed 's/^X//' << 'SHAR_EOF' > MANIFEST &&
X-rw-r--r--   1 wht      wht         3601 Jan  5 20:52 CMOSstime.c
X-rw-r--r--   1 wht      wht         1418 Jan  5 20:56 Makefile
X-rw-r--r--   1 wht      wht        24170 Jan  5 20:53 NBSsetclk.c
X-rw-r--r--   1 wht      wht         3793 Jan  5 20:56 README
X-rw-r--r--   1 wht      wht         3746 Jan  5 20:53 at_cmos.h
X-rw-r--r--   1 wht      wht         3964 Jan  5 20:53 cmos_disp.c
X-rw-r--r--   1 wht      wht         4600 Jan  5 20:54 dev_cmos.c
X-rw-r--r--   1 wht      wht          661 Jan  5 20:54 dev_cmos.h
X-rw-r--r--   1 wht      wht         1250 Jan  5 20:55 set_24hr.c
SHAR_EOF
chmod 0644 MANIFEST || echo "restore of MANIFEST fails"
if [ $TOUCH = can ]
then
    touch -m 0117011490 MANIFEST
fi
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
Xcmostime3 AT CMOS RAM TIME UTILITIES FOR SCO UNIX AND XENIX V/286&386
X...gatech!kd4nc!n4hgf!wht (wht%n4hgf@gatech.edu) - Wed Dec 27 1989
X
XOverview
X---------------------------------------------------------------------
XSCO UNIX and XENIX supports the AT cmos ram with two devices (/dev/cmos,
X/dev/clock), programs /etc/setclock and /lib/cvtdate and a shell script
X/etc/asktime.  However, there is no way to set the system time or the
Xcmos clock ACCURATELY using these tools since seconds are not in the
Xparadigm of setclock or /dev/clock.  One can, however, set the cmos
Xclock accurately by the direct manipulation of /dev/cmos.  By reading
X/dev/cmos, one can get the correct time and set the system time with
Xstime(S).
X
XThis collection of UNIX/XENIX V programs allows you to:
X
X1) set the AT cmos clock and system time very accurately by calling
X   the Naval Observatory ((202)653-0351 in DC) using NBSsetclk,
X
X2) set the system clock from the (somewhat drifty) cmos clock
X   by using CMOSstime,
X
X3) display "interesting" things in the cmos ram by using cmos_disp.
X
XThese programs have been proven to work on the Compaq Deskpro 286
Xand 386 using SCO XENIX/286 2.2.1 and XENIX/386 2.3.1.
X
XNBSsetclk
X---------------------------------------------------------------------
XNBSsetclk assumes a Hayes modem is connected to the line and that
Xcommand recognition is enabled.  /dev/tty1a is used by default.  The
Xprogram tries up to 40 times (40 seconds) to read the time, making it
Xlikely that you will succeed.  However, the program will terminate
Xbefore the minimum 1 minute connect charge has expired.  NBSsetclk MUST
Xbe run by root.  Why waste a long distance call only to have stime()
Xfail?  Most users will use the default parameters of this program by
Xinvoking it with
X    NBSsetclk -
XRunning the program with no parameters gives you the options available.
X
XExit status codes for the NBSsetclk:
X1-n  signal values if program killed
X200  illogical cmos device behavior (when reading clock)
X249  stime() call failed
X250  could not open communications line
X251  /dev/cmos read&write access denied
X252  user is not root
X253  usage
X254  couldn't get time from line (after 40 retries! BAD line conditions)
X255  couldn't establish a connection
X
XCMOSstime
X---------------------------------------------------------------------
XCMOStime reads the cmos clock and sets the system time to the second.
XRun it in your /etc/rc in place of the rather klunky 'asktime'.  The
Xprogram returns exit status 0 if it succeeds, 1 for most failures
X(stime() failure or /dev/cmos read access failure), or 200 for the rare
Xcases where the cmos device appears to be acting up.
X
Xcmos_disp
X---------------------------------------------------------------------
XThis is an experimental program that displays information contained
Xin the cmos ram.  It has some bugs in it (on my systems, it reports
Xno floppy drives, when I in fact have one).  The information used to
Xbuild the program came from the sketchy notes in the IBM AT Technical
XReference Manual.  Look in header file 'at_cmos.h' and source file
X'cmos_disp.c' for notes I have made about empirical "discoveries".
XThere are certainly some discrepancies, particularly on machines
Xother than the IBM AT.
X
Xset_24hr.c
X---------------------------------------------------------------------
XOnce or twice during a power main glitch, the 24-hour mode bit got
Xreset.  This program sets the bit.
X
XAcknowlegments
X---------------------------------------------------------------------
XThe routines for converting mm/dd/yy hh:mm:ss to seconds since
Xthe epoch were adapted from the 'tm_to_time.c' module in Emmet P.
XGray's conversion of arc to unix.
X
XThe concepts of parsing the Naval Observatory data stream came from
Xan anonymous author's nbs.c (which read the data stream from stdin).
SHAR_EOF
chmod 0644 README || echo "restore of README fails"
if [ $TOUCH = can ]
then
    touch -m 0105205690 README
fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#  CHK=0xDF23
X# Makefile for cmos/rtc programs
X#+:EDITS:
X#:02-03-1989-19:46-wht-386 release
X
XSHELL = /bin/sh
X
X.SUFFIXES:
X.SUFFIXES: .o .c .h  
X
XC_LD_COMMON = -i -s
XCFLAGS  = -c -O -K $(C_LD_COMMON)
XLIB = -lx
X#.c.o:;	fcrc -u $*.c ; $(CC) $(CFLAGS) $*.c 
X
XNBSSETCLK_OFILES = \
X	NBSsetclk.o\
X	dev_cmos.o
X
XCMOSSTIME_OFILES = \
X	CMOSstime.o\
X	dev_cmos.o
X
XCMOS_DISP_OFILES = \
X	cmos_disp.o\
X	dev_cmos.o
X
XS24H_DISP_OFILES = \
X	set_24hr.o\
X	dev_cmos.o
X
XSHAR_FILES = \
X	README\
X	Makefile\
X	CMOSstime.c\
X	NBSsetclk.c\
X	at_cmos.h\
X	cmos_disp.c\
X	dev_cmos.c\
X	dev_cmos.h\
X	set_24hr.c
X
Xall: NBSsetclk CMOSstime cmos_disp
X
XNBSsetclk: $(NBSSETCLK_OFILES)
X	$(CC) $(C_LD_COMMON) $(NBSSETCLK_OFILES) $(LIB) -o $@
X
XCMOSstime: $(CMOSSTIME_OFILES)
X	$(CC) $(C_LD_COMMON) $(CMOSSTIME_OFILES) $(LIB) -o $@
X
Xcmos_disp: $(CMOS_DISP_OFILES)
X	$(CC) $(C_LD_COMMON) $(CMOS_DISP_OFILES) $(LIB) -o $@
X
Xset_24hr: $(S24H_DISP_OFILES)
X	$(CC) $(C_LD_COMMON) $(S24H_DISP_OFILES) $(LIB) -o $@
X
Xshar:
X	ls -l $(SHAR_FILES) > MANIFEST
X	shar -c -ncmostime3 -l30 -ocmostime3. MANIFEST $(SHAR_FILES)
X
Xclean:
X	-rm -f *.o
X
Xclobber: clean
X	rm -f NBSsetclk CMOSstime cmos_disp set_24hr \
X		cmostime.sh.1 cmostime.sh.2 MANIFEST
X
XMANIFEST: $(SHAR1_FILES) $(SHAR2_FILES)
X	echo 'List of files in cmostime.sh.{1,2}' > MANIFEST
X	ls -l $(SHAR1_FILES) $(SHAR2_FILES) > MANIFEST
X
XNBS_setclk.o: at_cmos.h dev_cmos.h
X
XCMOSstime.o: dev_cmos.h
X
Xcmos_disp.o: at_cmos.h dev_cmos.h
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
if [ $TOUCH = can ]
then
    touch -m 0105205690 Makefile
fi
echo "x - extracting CMOSstime.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > CMOSstime.c &&
X/* CHK=0xFC70 */
X/* vi: set tabstop=4 shiftwidth=4: */
X/*+-------------------------------------------------------------------------
X	CMOSstime.c -- read cmos clock then stime()
X	...!gatech!kd4nc!n4hgf!wht
X
X  Defined functions:
X	date_to_epochsecs(year,month,day,hour,min,sec)
X	days_since_epoch(year,month,day)
X	leap_year(yr)
X	main(argc,argv,envp)
X
X--------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:12-04-1989-20:14-wht-support UNIX 3.2 */
X/*:02-03-1989-19:50-wht-386 release */
X/*:07-23-1988-18:59-wht-release */
X/*:07-22-1988-19:34-wht-creation */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <time.h>
X
X#include "dev_cmos.h"
X
Xint leap_year(int );
Xint days_since_epoch(int ,int ,int );
Xlong date_to_epochsecs(int ,int ,int ,int ,int ,int );
X
Xchar *ctime();
Xint stime(long *);
Xlong time(long *);
X
Xchar *cmos = "/dev/cmos";
X
X/*+-------------------------------------------------------------------------
X	leap_year(yr) -- returns 1 if leap year, 0 otherwise 
X--------------------------------------------------------------------------*/
Xint
Xleap_year(yr)
Xint yr;
X{
X	return((yr % 4 == 0) && (yr % 100 != 0) || (yr % 400 == 0));
X}	/* end of leap_year */
X
X/*+-------------------------------------------------------------------------
X	days_since_epoch(year,month,day)
XReturn the number of days between Jan 1, 1970 and year,month,day
Xyear is full year (e.g., 1988)
Xmonth is 0-11
Xday is 0-30 (must be legal day in month)
X--------------------------------------------------------------------------*/
Xint
Xdays_since_epoch(year,month,day)
Xint year;
Xint month;
Xregister int day;
X{
Xregister int mm;
Xregister int yy;
Xstatic char days_per_month[] = {31,28,31,30,31,30,31,31,30,31,30,31};
X
X	day++;			/* adjust for day 0-n instead of 1-n */
X
X	for(yy = 1970; yy < year; ++yy) 
X	{
X		day += 365;
X		if(leap_year(yy))
X			day++;
X	}
X	for(mm = 0; mm < month; ++mm)
X		day += days_per_month[mm] + (mm == 1 && leap_year(yy));
X
X	return(day);
X
X}	/* end of days_since_epoch */
X
X/*+-------------------------------------------------------------------------
X	date_to_epochsecs(year,month,day,hour,min,sec)
XConvert arguments into long seconds since 1/1/1970
Xyear is full year (e.g., 1988)
Xmonth is 0-11
Xday is 0-30 (must be legal day in month)
Xhour is 0-23, min and sec 0-59
X--------------------------------------------------------------------------*/
Xlong
Xdate_to_epochsecs(year,month,day,hour,min,sec)
Xint year;
Xint month;
Xint day;
Xint hour;
Xint min;
Xint sec;
X{
Xregister int m1;
Xregister int m2;
Xlong t;
Xstruct tm *tp;
Xstruct tm *localtime();
X
X	t = (days_since_epoch(year,month,day) - 1) * 86400L
X		+ (hour * 3600L) + (min * 60L) + sec;
X#if !defined(M_UNIX)
X	/* correct for the time zone */
X	tp = localtime(&t);
X	m1 = tp->tm_hour * 60 + tp->tm_min;
X	m2 = (hour * 60) + min;
X	t -= ((m1 - m2 + 720 + 1440) % 1440 - 720) * 60L;
X#endif
X
X	return(t);
X
X}	/* end of date_to_epochsecs */
X
X/*+-------------------------------------------------------------------------
X	main(argc,argv,envp)
X--------------------------------------------------------------------------*/
Xmain(argc,argv,envp)
Xint argc;
Xchar **argv;
Xchar **envp;
X{
Xint year,month,day,hour,min,sec;
Xint fdcmos;
Xlong now;
X
X	setbuf(stdout,NULL);
X	setbuf(stderr,NULL);
X
X	if((fdcmos = open(cmos,O_RDONLY)) < 0)
X	{
X		perror(cmos);
X		exit(1);
X	}
X
X	get_clock(fdcmos,&year,&month,&day,&hour,&min,&sec);
X	now = date_to_epochsecs(year,month,day,hour,min,sec);
X	if(stime(&now))
X	{
X		perror("stime");
X		exit(1);
X	}
X	time(&now);
X	fputs("System time after stime(): ",stdout);
X	fputs(ctime(&now),stdout);
X
X	exit(0);
X}	/* end of main */
SHAR_EOF
chmod 0644 CMOSstime.c || echo "restore of CMOSstime.c fails"
if [ $TOUCH = can ]
then
    touch -m 0105205290 CMOSstime.c
fi
echo "x - extracting NBSsetclk.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > NBSsetclk.c &&
X/* CHK=0x9B09 */
X/* vi: set tabstop=4 shiftwidth=4: */
X/*+-----------------------------------------------------------------------
X  NBSsetclk.c -- call NBS, get time, hangup QUICKly, set system time,
X                 update cmos clock (/dev/cmos)
X	...!gatech!kd4nc!n4hgf!wht
X
X  Defined functions:
X	create_lock_file(lock_file_name)
X	hangup(sig)
X	hayes_dial()
X	hayes_modem_init(cmd)
X	hayes_send_cmd(cmd)
X	lclose()
X	lgetc(char_rtnd)
X	lgetc_timeout(timeout_msec)
X	lgets_timeout(lrwt)
X	lkill_buf()
X	lock_tty()
X	lopen()
X	lputc(lchar)
X	lputs_paced(pace_msec,string)
X	lset_baud_rate(ioctl_flag)
X	lset_parity(ioctl_flag)
X	main(argc,argv,envp)
X	make_lock_name(ttyname,lock_file_name)
X	other_lock_name(first_lock_name)
X	unlock_tty()
X	usage()
X	valid_baud_rate(baud)
X
X  Note: must be root to execute
X
X  Exit status codes for the program:
X  1-n  signal values if program killed
X  200  illogical cmos device behavior (when reading clock)
X  249  stime() call failed
X  250  could not open communications line
X  251  /dev/cmos read&write access denied
X  252  user is not root
X  253  usage
X  254  couldn't get time from line (after 40 retries! BAD line conditions)
X  255  could not establish a connection or line error
X
X------------------------------------------------------------------------*/
X/*+:EDITS:*/
X/*:12-27-1989-15:46-wht-use getopt */
X/*:12-27-1989-15:42-wht-time was of by one second (bitch,bitch,bitch) */
X/*:12-04-1989-20:14-wht-support UNIX 3.2 */
X/*:05-18-1989-15:12-wht-improve hangup() error reporting */
X/*:05-18-1989-15:04-wht-use ltoggle_dtr: close/open chg'd baudrate */
X/*:02-03-1989-19:50-wht-386 release */
X/*:12-07-1988-15:13-wht-show cmos time before setting it */
X/*:07-23-1988-19:03-wht-release */
X/*:07-23-1988-13:11-wht-get good parsed time before hanging up w/max retries */
X/*:07-23-1988-12:50-wht-do not use setclock ... messes up new system time */
X/*:07-22-1988-20:17-wht-change output format */
X/*:07-18-1988-22:07-wht-working! */
X/*:07-18-1988-17:27-wht-creation */
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/ioctl.h>
X#include <time.h>
X#include <string.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <termio.h>
X
X#include "dev_cmos.h"
X
X#ifndef ushort
X#define ushort	unsigned short
X#endif
X#ifndef uchar
X#define uchar unsigned char
X#endif
X#ifndef uint
X#define uint	unsigned int
X#endif
X#ifndef ulong
X#define ulong	unsigned long
X#endif
X
Xvoid usage(void);
Xvoid hangup(int );
Xint make_lock_name(char *,char *);
Xint create_lock_file(char *);
Xchar *other_lock_name(char *);
Xint lock_tty(void );
Xvoid unlock_tty(void );
Xint valid_baud_rate(unsigned int );
Xint lset_baud_rate(int );
Xvoid lset_parity(int );
Xvoid lgetc(char *);
Xvoid lputc(char );
Xvoid lputs_paced(int ,char *);
Xchar *lgets_timeout(struct lrwt *);
Xint lgetc_timeout(unsigned long );
Xvoid lkill_buf(void );
Xint lopen(void );
Xvoid lclose(void );
Xint hayes_send_cmd(char *);
Xint hayes_dial(void );
X
Xushort	geteuid();
Xushort	getuid();
Xlong	nap(long);
Xlong time(long *);
Xchar *ctime();
X
Xtypedef struct lrwt	/* param to lgets_timeout in eculine.c */
X{
X	ulong to1;		/* timeout for 1st character (granularity 20) */
X	ulong to2;		/* timeout for each next char (granularity 20) */
X	int raw_flag;	/* !=0, rtn full buffer, ==0, rtn filtered hayes result */
X	char *buffer;	/* buffer to fill */
X	int bufsize;	/* size of buffer */
X	int count;		/* from proc, count rcvd */
X}	LRWT;
X
X#define	EPOCH		40587					/* UNIX starts JD 2440587, */
X#define	leap(y,m)	((y+m-1 - 70%m) / m)	/* also known as 1/1/70 */
X#define	NBSTONE		'*'						/* time "hack" */
X#define	NBSFMT		"%05ld %03d %02d%02d%02d UTC"
X
X#define pf	printf
X#define	ff	fprintf
X#define se	stderr
X#define so	stdout
X
X/* lopen() and related routines error codes */
X#define LOPEN_INVALID	-1		/* for invalid tty name */
X#define LOPEN_UNKPID	-2		/* unknown pid using line */
X#define LOPEN_LCKERR	-3		/* lock file open error */
X#define LOPEN_NODEV		-4		/* device does not exist */
X#define LOPEN_OPNFAIL	-5		/* count not open line */
X#define LOPEN_ALREADY	-6		/* line already open */
X
Xextern char *revision;		/* ecurev.c temp file from buildrev */
Xextern char *numeric_revision;	/*ecunumrev.c */
X
Xchar LLCKname[128];		/* lock file name */
Xint Lmodem_already_init = 0;
Xchar Ltelno[64];		/* telephone number for remote or null */
Xchar Lline[64];			/* line name */
Xint Liofd;				/* file descriptor for line */
Xint Lparity;			/* 0==NONE, 'e' == even, 'o' == odd */
Xstruct termio	Ltermio;	/* attributes for the line to remote */
Xuint Lbaud;				/* baud rate */
Xushort euid;
Xushort uid;
Xchar *cmos = "/dev/cmos";
X
X/*+-------------------------------------------------------------------------
X	usage()
X--------------------------------------------------------------------------*/
Xvoid
Xusage()
X{
X	ff(se,"Usage: NBSsetclk [-][-e][-o][-n][-b#][-t#][-l<name>]\n");
X	ff(se,"Defaults 1200-N %s %s\n",Ltelno,Lline);
X	ff(se," -        use defaults\n");
X	ff(se," -e       even parity\n");
X	ff(se," -o       odd parity\n");
X	ff(se," -n       no parity\n");
X	ff(se," -b#      baud rate\n");
X	ff(se," -t#      telephone number\n");
X	ff(se," -l<name> line (e.g., /dev/tty2A)\n");
X	exit(253);
X
X}	/* end of usage */
X
X/*+-----------------------------------------------------------------------
X	hangup(sig) -- terminate program (with comm line cleanup)
X------------------------------------------------------------------------*/
Xvoid
Xhangup(sig)
Xint sig;
X{
Xvoid	lclose();
X
X	ff(se,"\nhangup %d (see code)\n",sig);
X	if(Liofd != -1)
X		lclose();			/* close line */
X	exit(sig);
X}	/* end of hangup */
X
X/*+-------------------------------------------------------------------------
X	make_lock_name(ttyname,lock_file_name)
X--------------------------------------------------------------------------*/
Xmake_lock_name(ttyname,lock_file_name)
Xregister char *ttyname;
Xchar *lock_file_name;
X{
X	if(strncmp(ttyname,"/dev/tty",8))
X		return(LOPEN_INVALID);
X
X	strcpy(lock_file_name,"/usr/spool/uucp/LCK..");
X	strcat(lock_file_name,ttyname + 8);
X	return(0);
X
X}	/* end of make_lock_name */
X
X/*+-----------------------------------------------------------------------
X	create_lock_file()
X
X  Returns 0 if lock file created, else error codes:
X	LOPEN_ if error
X    else pid of process currently busy on device
X  Everybody's uucp is diffeent - hack this if you like
X------------------------------------------------------------------------*/
Xcreate_lock_file(lock_file_name)
Xchar *lock_file_name;
X{
Xregister int fdlock;
Xint pid;
Xint old_umask;
X
X	old_umask = umask(0);
X
X	if((fdlock = open(lock_file_name,O_CREAT | O_EXCL | O_RDWR,0666)) < 0)
X	{		/* file already exists */
X		if((fdlock = open(lock_file_name,O_RDWR,0666)) < 0)
X		{
X			umask(old_umask);
X			return(LOPEN_LCKERR);
X		}
X
X		if(read(fdlock,(char *)&pid,sizeof(pid)) > 0)
X		{
X			if(kill(pid,0) && (errno == ESRCH))	/* is owner dead? */
X			{
X				pid = getpid();
X				lseek(fdlock,0L,0);
X				write(fdlock,(char *)&pid,sizeof(pid));
X				close(fdlock);
X				umask(old_umask);
X				return(0);
X			} 
X			/* owner pid still active with lock */
X			close(fdlock);
X			umask(old_umask);
X			return(pid);
X		}
X		close(fdlock);
X		umask(old_umask);
X		return(LOPEN_UNKPID);
X	} 
X	pid = getpid();
X	write(fdlock,(char *)&pid,sizeof(pid));
X	close(fdlock);
X	chmod(lock_file_name,0666);
X	umask(old_umask);
X	return(0);
X
X}	/* end of create_lock_file */
X
X/*+-------------------------------------------------------------------------
X	other_lock_name(first_lock_name)
X--------------------------------------------------------------------------*/
Xchar *
Xother_lock_name(first_lock_name)
Xchar *first_lock_name;
X{
Xregister int itmp;
Xstatic char other_lock_name[64];
X
X	strcpy(other_lock_name,first_lock_name);
X	itmp = strlen(other_lock_name) - 1;
X	if(islower(other_lock_name[itmp]))
X		other_lock_name[itmp] = toupper(other_lock_name[itmp]);
X	else if(isupper(other_lock_name[itmp]))
X		other_lock_name[itmp] = tolower(other_lock_name[itmp]);
X
X	return(other_lock_name);
X		
X}	/* end of other_lock_name */
X
X/*+-------------------------------------------------------------------------
X	lock_tty()
X--------------------------------------------------------------------------*/
Xlock_tty()
X{
Xregister int itmp;
Xstruct stat ttystat;
X
X	if(itmp = make_lock_name(Lline,LLCKname))
X		return(itmp);
X
X	if(stat(Lline,&ttystat) < 0)
X		return(LOPEN_NODEV);
X
X	if(itmp = create_lock_file(LLCKname))
X		return(itmp);
X
X	if(itmp = create_lock_file(other_lock_name(LLCKname)))
X	{
X		unlink(LLCKname);
X		LLCKname[0] = 0;
X		return(itmp);
X	}
X
X}	/* end of lock_tty */
X
X/*+-----------------------------------------------------------------------
X	void unlock_tty()
X------------------------------------------------------------------------*/
Xvoid
Xunlock_tty()
X{
X
X	if(LLCKname[0] == 0)
X		return;
X	unlink(LLCKname);
X	unlink(other_lock_name(LLCKname));
X	LLCKname[0] = 0;
X}	/* end of unlock_tty */
X
X/*+-------------------------------------------------------------------------
X	valid_baud_rate(baud) -- returns (positive) baud rate selector
Xor -1 if invalid baud rate
X--------------------------------------------------------------------------*/
Xvalid_baud_rate(baud)
Xuint	baud;
X{
X	switch(baud)
X	{
X		case 110: return(B110);
X		case 300: return(B300);
X		case 600: return(B600);
X		case 1200: return(B1200);
X		case 2400: return(B2400);
X		case 4800: return(B4800);
X		case 9600: return(B9600);
X		case 19200: return(EXTA);
X		case 38400: return(EXTB);
X		default: return(-1);
X	}
X}	/* end of valid_baud_rate */
X
X/*+-----------------------------------------------------------------------
X	lset_baud_rate(ioctl_flag)
X
X  If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Ltermio)
X  is executed after setting baud rate
X------------------------------------------------------------------------*/
Xlset_baud_rate(ioctl_flag)
Xint ioctl_flag;
X{
Xint baud_selector = valid_baud_rate(Lbaud);
X
X	if(baud_selector < 0)
X	{
X		ff(se,"invalid baud rate: %u\n",Lbaud);
X		ff(se,"valid rates: 110,300,600,1200,2400,4800,9600,19200\n");
X		return(1);
X	}
X	Ltermio.c_cflag &= ~CBAUD;
X	Ltermio.c_cflag |= baud_selector;
X
X	if(ioctl_flag)
X		 ioctl(Liofd,(int)TCSETA,(char *)&Ltermio);
X	return(1);
X
X}	/* end of lset_baud_rate */
X
X/*+-----------------------------------------------------------------------
X	lset_parity(ioctl_flag)
X
X  If 'ioctl_flag' is set,then ioctl(Liofd,TCSETA,&Ltermio)
X  is executed after setting parity
X------------------------------------------------------------------------*/
Xvoid
Xlset_parity(ioctl_flag)
Xint ioctl_flag;
X{
X	Ltermio.c_cflag &= ~(CS8 | PARENB | PARODD);
X	switch(Lparity)
X	{
X		case 'e':
X			Ltermio.c_cflag |= CS7 | PARENB;
X			Ltermio.c_iflag |= ISTRIP;
X			break;
X		case 'o':
X			Ltermio.c_cflag |= PARODD | CS7 | PARENB;
X			Ltermio.c_iflag |= ISTRIP;
X			break;
X		default:
X			ff(se,"invalid parity: %c ... defaulting to no parity\n");
X		case 0:
X		case 'n':
X			Ltermio.c_cflag |= CS8;
X			Ltermio.c_iflag &= ~(ISTRIP);
X			Lparity = 0;
X			break;
X	}			
X
X	if(ioctl_flag)
X		 ioctl(Liofd,(int)TCSETA,(char *)&Ltermio);
X
X}	/* end of lset_parity */
X
X/*+-------------------------------------------------------------------------
X	lgetc(char_rtnd)
X--------------------------------------------------------------------------*/
Xvoid
Xlgetc(char_rtnd)
Xchar *char_rtnd;
X{
X	if(read(Liofd,char_rtnd,1) < 1)
X	{
X		perror("line read error");
X		hangup(255);
X	}
X}	/* end of lgetc */
X
X/*+-----------------------------------------------------------------------
X	lputc(lchar) -- write lchar to comm line
X------------------------------------------------------------------------*/
Xvoid
Xlputc(lchar)
Xchar lchar;
X{
Xregister int itmp;
X
X	if((itmp = write(Liofd,&lchar,1)) < 1)
X	{
X		if(itmp < 0)
X			perror("\nline write error");
X		else
X			fputs("\nline write error\n",se);
X		hangup(255);
X	}
X}	/* end of lputc */
X
X/*+-----------------------------------------------------------------------
X	lputs_paced(pace_msec,string) -- write string to comm line
X  with time between each character 
X------------------------------------------------------------------------*/
Xvoid
Xlputs_paced(pace_msec,string)
Xregister int pace_msec;
Xregister char *string;
X{
Xregister long msec = (pace_msec) ? (long)pace_msec : 20L;
X
X	while(*string)
X	{
X		lputc(*string++);
X		nap(msec);
X	}
X
X}	/* end of lputs_paced */
X
X/*+-------------------------------------------------------------------------
X	char *lgets_timeout(LRWT *)
X
XRefer to LWRT structure.
X
Xto1 and to2 are unsigned long values in milliseconds (not currently
Xsupported well under BSD4); to1 is the time to wait for the first
Xcharacter, to2 the time to wait for subsequent characters.
X
Xif raw_flag 0,     non-printables are stripped from beginning
X                   and end of received characters (i.e., modem
X                   response reads); NULs discarded, parity stripped
Xif raw_flag 1,     full raw read buffer returned
Xif raw_flag 2,     full buffer, NULs discarded, parity stripped
X
Xbuffer is address to read chars into
X
Xbufsize is buffer max size (allowing room for terminating null) which
Xshould be at least 2 if raw_size includes 0x80 bit, else at least 12
Xcharacters if 0x80 omitted.
X
Xcount is a int which, at return, receives the actual count read
X
X--------------------------------------------------------------------------*/
Xchar *
Xlgets_timeout(lrwt)
XLRWT	*lrwt;
X{
Xregister int actual_count = 0;
Xregister char *cptr = lrwt->buffer;
Xint max_count = lrwt->bufsize;
Xchar *rtn_val;
Xint timeout_counter;
Xint qc1,qc2;
Xlong quantum,ltmp;
X
X/* minimum wait is 60 msec */
X	if(Lbaud < 300)
X		if(lrwt->to2 < 300L) lrwt->to2 = 300L;
X	if(Lbaud < 1200)
X		if(lrwt->to2 < 200L) lrwt->to2 = 200L;
X	else
X		if(lrwt->to2 < 60L) lrwt->to2 = 60L;
X
X/* shortest interval */
X	ltmp = (lrwt->to1 < lrwt->to2) ? lrwt->to1 : lrwt->to2;
X
X/* calculate wait quantum */
X	quantum = ltmp / 10L;				/* try for ten ticks */
X	if(quantum < 20L)
X		quantum = 20L;
X	qc1 = lrwt->to1 / quantum;
X	if(!qc1) qc1 = 1L;
X	qc2 = lrwt->to2 / quantum;
X	if(!qc2) qc2 = 1L;
X
X/* perform the lrtw function
X   input: qc1 is first nap count (for first charcters) 
X          qc2 is 2nd nap count (for subsequent characters) 
X          quantum is the nap period in milliseconds
X          cptr is char* to receive read string
X          max_count is max number of characters incl null
X          lrwt->raw_flag as described above
X
X  output: lrwt->count is actual count of return result
X          lrwt->buffer is return read buffer
X*/
X	max_count--;				/* leave room for null */
X
X	lrwt->raw_flag &= 0x0F;		/* get rid of 0xF0 flags */
X	timeout_counter = qc1;		/* first timeout */ 
X	*cptr = 0;					/* init result string */
X	while(timeout_counter--)
X	{
X		nap(quantum);
X		while(rdchk(Liofd))
X		{
X			lgetc(cptr);
X			if(lrwt->raw_flag != 1)
X			{
X				*cptr &= 0x7F;
X				if(*cptr == 0)
X					continue;
X			}
X
X			*++cptr = 0;
X			actual_count++;
X			if(--max_count == 0)
X				goto READ_LINE_POST_PROCESS;
X			timeout_counter = qc2;
X		}
X	}
X
XREAD_LINE_POST_PROCESS:
X	if(lrwt->raw_flag)
X	{
X		lrwt->count = actual_count;
X		return(lrwt->buffer);
X	}
X	cptr = lrwt->buffer;
X	while(((*cptr >0) && (*cptr < 0x20)) || (*cptr >= 0x7F))
X		cptr++;
X	rtn_val = cptr;
X	actual_count = 0;
X	while(((*cptr &= 0x7F) >= 0x20) && (*cptr <= 0x7E))
X	{
X		cptr++;
X		actual_count++;
X	}
X	*cptr = 0;
X	strcpy(lrwt->buffer,rtn_val);
X	lrwt->count = actual_count;
X	return(lrwt->buffer);
X}	/* end of lgets_timeout */
X
X/*+-------------------------------------------------------------------------
X	lgetc_timeout(timeout_msec)
X
X reads one character from line unless timeout_msec passes with no receipt.
X timeout_msec < 20 msec becomes 20 msec
X return char if received, else -1 if timeout
X--------------------------------------------------------------------------*/
Xint
Xlgetc_timeout(timeout_msec)
Xulong	timeout_msec;
X{
XLRWT	lr;
Xchar getc_buf[2];		/* room for one char + null */
X
X	lr.to1 = timeout_msec;
X	lr.to2 = timeout_msec;
X	lr.raw_flag = 1;		/* full raw read */
X	lr.buffer = getc_buf;
X	lr.bufsize = sizeof(getc_buf);
X	lgets_timeout(&lr);
X	return(  (lr.count == 1) ? (int)getc_buf[0] : -1 );
X
X}	/* end of lgetc_timeout */
X
X/*+-------------------------------------------------------------------------
X	lkill_buf()
X--------------------------------------------------------------------------*/
Xvoid
Xlkill_buf()
X{
X	ioctl(Liofd,(int)TCFLSH,(char *)2); /* flush input and output */
X}	/* end of lkill_buf */
X
X/*+----------------------------------------------------------------------
X	lopen()
Xreturns negative LOPEN_ codes if failure else positive pid using line
Xelse 0 if successful open
X------------------------------------------------------------------------*/
Xint
Xlopen()
X{
Xregister int	itmp;
X
X	if(Liofd >= 0)
X		return(LOPEN_ALREADY);
X	if(itmp = lock_tty())		/* get lock file */
X		return(itmp);
X	Liofd = open(Lline,O_RDWR | O_NDELAY,0777);
X	if(Liofd < 0)
X		return(LOPEN_OPNFAIL);
X	else
X	{
X		ioctl(Liofd,(int)TCGETA,(char *)&Ltermio);
X		Ltermio.c_iflag = (IGNPAR | IGNBRK | IXOFF );
X		Ltermio.c_cflag |= (CREAD | HUPCL);
X		Ltermio.c_lflag = 0;
X
X		Ltermio.c_cc[VMIN]   = 1;
X		Ltermio.c_cc[VTIME]  = 1;
X
X		lset_baud_rate(0);		/* do not perform ioctl */
X		lset_parity(1);			/* do perform ioctl */
X	}
X
X	return(0);
X
X}	/* end of lopen */
X
X/*+-----------------------------------------------------------------------
SHAR_EOF
echo "End of cmostime3 part 1"
echo "File NBSsetclk.c is continued in part 2"
echo "2" > s3_seq_.tmp
exit 0
 
----------------------------------------------------------------------------
Warren Tucker                     emory!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US
"I was 35 years old before I knew a pie was meant to be eaten." - Moe Howard