erc@khijol.UUCP (Edwin R. Carp) (01/17/90)
Here's the source for nbs_time.c that I scarfed from archive@mgse. I'm posting the source, rather than the binary+source, because by the time I wake up tomorrow morning, it'll probably have been ported to the Amiga, the PC, the Mac, and VMS, not to mention MVS, TSO, VM, and a host of others :-) Enjoy! ----------------------------- 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 */ /* The following statement was added because of a bug in the original code */ lt->tm_mon++; 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 */ -- Ed Carp N7EKG/5 (28.3-28.5) uunet!cs.utexas.edu!khijol!erc Austin, Texas (512) 832-5884 "Good tea. Nice house." - Worf
wht@tridom.uucp (Warren Tucker) (01/17/90)
I just posted to alt.sources cmostime3, a two-part shar, which was an expansion on my previous program, nbs_time.c. The whole business was inspired by comp.sources.misc v03i079. The original author did all the hard work. For nbs_time.c, I just put a bunch of async junk around it to autodial and otherwise make it a standalone program. cmostime built on this to avoid using the inexact /etc/setclock and a few other goodies. v03i079 contains a GREAT program utc.c which allows your system to mimic NBS and provide esentially the same service via a local call. Only the most ultimate time freaks who've replaced their PC's crystal with an atomic clock can tell the difference (I'm pretty bad, but not that bad) :-). -- ------------------------------------------------------------------ Warren Tucker, Tridom Corporation ...!gatech!emory!tridom!wht home address: ...!gatech!kd4nc!n4hgf!wht
bob@MorningStar.Com (Bob Sutterfield) (01/18/90)
In article <899@tridom.uucp> wht@tridom.uucp (Warren Tucker) writes:
v03i079 contains a GREAT program utc.c which allows your system to
mimic NBS and provide esentially the same service via a local call.
Only the most ultimate time freaks who've replaced their PC's
crystal with an atomic clock can tell the difference (I'm pretty
bad, but not that bad) :-).
I'd hope that only folks either running a local radio clock, or a low-
stratum NTP peer, would offer their system's time as a community
standard. However, this would be a really nice service for Internet-
connected folks to offer to their UUCP-only neighbors.
thad@cup.portal.com (Thad P Floryan) (01/19/90)
In article <BOB.90Jan17123008@volitans.MorningStar.Com> by bob@MorningStar.Com (Bob Sutterfield) to alt.sources,rec.ham-radio, he writes: " In article <899@tridom.uucp> wht@tridom.uucp (Warren Tucker) writes: v03i079 contains a GREAT program utc.c which allows your system to mimic NBS and provide esentially the same service via a local call. Only the most ultimate time freaks who've replaced their PC's crystal with an atomic clock can tell the difference (I'm pretty bad, but not that bad) :-). I'd hope that only folks either running a local radio clock, or a low- stratum NTP peer, would offer their system's time as a community standard. However, this would be a really nice service for Internet- connected folks to offer to their UUCP-only neighbors. " Is there some ESP going on here? :-) I've put together a prototype system that does just what Karl describes. My time reference is a HeathKit GC-1000 "Most Accurate Clock" which locks onto NIST's (formerly NBS') WWV at 5, 10 or 15 MHz to provide +/- 10 mSec Universal Time Coordinated on its RS-232c port. I've been testing the setup since: $ loglook utc Login ID First Last Name -------- ---------------------- ---------------------- -------------------- utc Sat 14-Oct-89 17:59:07 Thu 18-Jan-90 23:12:28 UTC time service ^^^^^^^^^ Note that date; 3 days later my antenna snapped during the earthquake, and I haven't repaired it ... I'm in Silicon Valley, and the antenna is a huge inverted "V" whose apex WAS at the top of a 40' tower. :-( At the moment, one of my systems calls the US Naval Observatory service in Washington DC every 2 days to maintain time-sync locally, but once I repair the antenna AND get some more phone lines installed, this service will be publicly online and I'll post its availability along with all the software. I use the service to coordinate time for all my LAN-based systems. The server provides a time reference identical to the USNO per: * jjjjj ddd hhmmss UTC where: jjjjj Julian date modulo 2400000 ddd days since beginning of year hhmmss time of day in Universal Time Coordinated based on a program by Michael Scott Baldwin of AT&T Bell Labs. If you'd like to install and provide such a service on your system, you need an accurate time reference (the Heath clock is my recommendation: kit price from their Winter 1990 Catalog No. 219 is $249.95 for the clock and $49.95 for the RS-232 interface (see page 28)), and: $ ls -l /usr/local/bin/utcs* -rwxr-xr-x 1 thad users 3156 Oct 14 17:22 /usr/local/bin/utcservice $ file /usr/local/bin/utcs* /usr/local/bin/utcservice: mc68k executable (shared demand paged with \ shared library) -F (0413 demand paged) and entries for /etc/passwd: utc::50:50:UTC time service:/usr/local/bin:/usr/local/bin/utcservice and /etc/group: utcpub::50:utc All a client system(s) need do is install the "capture" program and execute it per: # must run this as super-user # echo "\nutc" | cu thadlabs | /usr/local/bin/utcset -s exit 0 from a crontab entry like the following: #Mn Hr Da Mo Da (0=SUN, 1=MON, 2=TUE, 3=WED, 4=THU, 5=FRI, 6=SAT) #of of of of of #Hr Da Mo Yr Wk Command # 03 3 * * * /bin/su root -c "/usr/local/bin/utcset.sh >/dev/null" assuming one has a /usr/lib/uucp/Systems (or L.sys) entry for the server. The above is how I've configured the service to date. Because some "cu" don't seem to respond to SIGPIPE properly, I'm planning on generalizing the client program to itself connect and retrieve the server info, and will post the whole package when it's complete. If someone would like to help (my time is VERY limited) and/or you'd like some more info, feel welcome to contact me: Thad Floryan [ thad@cup.portal.com (OR) ..!sun!portal!cup.portal.com!thad ]
barton@holston.UUCP (Barton A. Fisk) (01/20/90)
Hey, this program is really spiffy, but what exactly is NBS? I am assuming it's a standard time sort of system, could some- one expound a bit for me and others who don't know? Thanks for the program... -- Barton A. Fisk | UUCP: {attctc,texbell}vector!holston!barton PO Box 1781 | (PSEUDO) DOMAIN: barton@holston.UUCP Lake Charles, La. 70602 | ---------------------------------------- 318-439-5984 | "Let him who is without sin cast the first stone"-JC