/* $NetBSD: clktest.c,v 1.1.1.1 2000/03/29 12:38:45 simonb Exp $ */ /* clktest.c,v 3.1 1993/07/06 01:05:23 jbj Exp * clktest - test the clock line discipline * * usage: clktest -b bps -f -t timeo -s cmd -c char1 -a char2 /dev/whatever */ #include #include #include #include #include #include #include #include #include #include #include "../include/ntp_fp.h" #include "../include/ntp.h" #include "../include/ntp_unixtime.h" #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) #if defined(ULT_2_0_SUCKS) #ifndef sigmask #define sigmask(m) (1<<(m)) #endif #endif #ifndef STREAM #ifndef CLKLDISC CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM; #endif #endif /* * Mask for blocking SIGIO and SIGALRM */ #define BLOCKSIGMASK (sigmask(SIGIO)|sigmask(SIGALRM)) /* * speed table */ struct speeds { int bps; int rate; } speedtab[] = { { 300, B300 }, { 1200, B1200 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, EXTA }, { 38400, EXTB }, { 0, 0 } }; char *progname; int debug; #ifdef CLKLDISC #define DEFMAGIC '\r' #endif #ifdef CLKLDISC # ifdef STREAM # include # ifdef HAVE_SYS_CLKDEFS_H # include # endif # define DEFMAGIC "\r" # endif #endif struct timeval timeout = { 0 }; char *cmd = NULL; int cmdlen; int docmd = 0; #ifdef CLKLDISC u_long magic1 = DEFMAGIC; u_long magic2 = DEFMAGIC; #endif #ifdef STREAM char magic[32]; #endif int speed = B9600; int ttflags = RAW|EVENP|ODDP; volatile int wasalarmed; volatile int iosig; struct timeval lasttv; extern u_long ustotslo[]; extern u_long ustotsmid[]; extern u_long ustotshi[]; /* * main - parse arguments and handle options */ int main( int argc, char *argv[] ) { int c; int errflg = 0; struct speeds *spd; u_long tmp; int fd; struct sgttyb ttyb; struct itimerval itimer; extern int ntp_optind; extern char *ntp_optarg; int alarming(); int ioready(); progname = argv[0]; #ifdef STREAM magic[0] = 0; #endif while ((c = ntp_getopt(argc, argv, "a:b:c:dfs:t:")) != EOF) switch (c) { #ifdef CLKLDISC case 'a': #endif case 'c': if (!atouint(ntp_optarg, &tmp)) { (void) fprintf(stderr, "%s: argument for -%c must be integer\n", progname, c); errflg++; break; } #ifdef CLKLDISC if (c == 'c') magic1 = tmp; else magic2 = tmp; #endif #ifdef STREAM magic[strlen(magic)+1] = '\0'; magic[strlen(magic)] = tmp; #endif break; case 'b': if (!atouint(ntp_optarg, &tmp)) { errflg++; break; } spd = speedtab; while (spd->bps != 0) if ((int)tmp == spd->bps) break; if (spd->bps == 0) { (void) fprintf(stderr, "%s: speed %lu is unsupported\n", progname, tmp); errflg++; } else { speed = spd->rate; } break; case 'd': ++debug; break; case 'f': ttflags |= CRMOD; break; case 's': cmdlen = strlen(ntp_optarg); if (cmdlen == 0) errflg++; else cmd = ntp_optarg; break; case 't': if (!atouint(ntp_optarg, &tmp)) errflg++; else { timeout.tv_sec = (long)tmp; docmd = 1; } break; default: errflg++; break; } if (errflg || ntp_optind+1 != argc) { (void) fprintf(stderr, #ifdef CLKLDISC "usage: %s [-b bps] [-c magic1] [-a magic2] [-f] [-s cmd] [-t timeo] tty_device\n", #endif #ifdef STREAM "usage: %s [-b bps] [-c magic1] [-c magic2]... [-f] [-s cmd] [-t timeo] tty_device\n", #endif progname); exit(2); } #ifdef STREAM if (!strlen(magic)) strcpy(magic,DEFMAGIC); #endif if (docmd) fd = open(argv[ntp_optind], O_RDWR, 0777); else fd = open(argv[ntp_optind], O_RDONLY, 0777); if (fd == -1) { (void) fprintf(stderr, "%s: open(%s): ", progname, argv[ntp_optind]); perror(""); exit(1); } if (ioctl(fd, TIOCEXCL, (char *)0) < 0) { (void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname); perror(""); exit(1); } /* * If we have the clock discipline, set the port to raw. Otherwise * we run cooked. */ ttyb.sg_ispeed = ttyb.sg_ospeed = speed; #ifdef CLKLDISC ttyb.sg_erase = (char)magic1; ttyb.sg_kill = (char)magic2; #endif ttyb.sg_flags = (short)ttflags; if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) { (void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname); perror(""); exit(1); } if (fcntl(fd, F_SETOWN, getpid()) == -1) { (void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname); perror(""); exit(1); } #ifdef CLKLDISC { int ldisc; ldisc = CLKLDISC; if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) { (void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname); perror(""); exit(1); } } #endif #ifdef STREAM if (ioctl(fd, I_POP, 0) >=0 ) ; if (ioctl(fd, I_PUSH, "clk") < 0) { (void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname); perror(""); exit(1); } if (ioctl(fd, CLK_SETSTR, magic) < 0) { (void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname); perror(""); exit(1); } #endif (void) gettimeofday(&lasttv, (struct timezone *)0); if (docmd) { /* * set non-blocking, async I/O on the descriptor */ iosig = 0; (void) signal(SIGIO, ioready); if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) { (void) fprintf(stderr, "%s: fcntl(F_SETFL): ", progname); perror(""); exit(1); } /* * Set up the alarm interrupt. */ wasalarmed = 0; (void) signal(SIGALRM, alarming); itimer.it_interval = itimer.it_value = timeout; setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0); doboth(fd); } doioonly(fd); } /* * doboth - handle both I/O and alarms via SIGIO */ int doboth( int fd ) { int n; int sawalarm; int sawiosig; int omask; fd_set fds; struct timeval tvzero; sawalarm = 0; sawiosig = 0; FD_ZERO(&fds); for (;;) { omask = sigblock(BLOCKSIGMASK); if (wasalarmed) { /* alarmed? */ sawalarm = 1; wasalarmed = 0; } if (iosig) { sawiosig = 1; iosig = 0; } if (!sawalarm && !sawiosig) { /* * Nothing to do. Wait for something. */ sigpause(omask); if (wasalarmed) { /* alarmed? */ sawalarm = 1; wasalarmed = 0; } if (iosig) { sawiosig = 1; iosig = 0; } } (void)sigsetmask(omask); if (sawiosig) { do { tvzero.tv_sec = tvzero.tv_usec = 0; FD_SET(fd, &fds); n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, &tvzero); if (n > 0) doio(fd); } while (n > 0); if (n == -1) { (void) fprintf(stderr, "%s: select: ", progname); perror(""); exit(1); } sawiosig = 0; } if (sawalarm) { doalarm(fd); sawalarm = 0; } } } /* * doioonly - do I/O. This avoids the use of signals */ int doioonly( int fd ) { int n; fd_set fds; FD_ZERO(&fds); for (;;) { FD_SET(fd, &fds); n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if (n > 0) doio(fd); } } /* * doio - read a buffer full of stuff and print it out */ int doio( int fd ) { register char *rp, *rpend; register char *cp; register int i; char raw[512]; struct timeval tv, tvd; int rlen; int ind; char cooked[2049]; static char *digits = "0123456789abcdef"; rlen = read(fd, raw, sizeof(raw)); if (rlen < 0) { (void) fprintf(stderr, "%s: read(): ", progname); perror(""); return; } if (rlen == 0) { (void) printf("Zero length read\n"); return; } cp = cooked; rp = raw; rpend = &raw[rlen]; ind = 0; while (rp < rpend) { ind = 1; if (isprint(*rp)) *cp++ = *rp; else { *cp++ = '<'; *cp++ = digits[((*rp)>>4) & 0xf]; *cp++ = digits[*rp & 0xf]; *cp++ = '>'; } if ( #ifdef CLKLDISC (*rp == (char)magic1 || *rp == (char)magic2) #else ( strchr( magic, *rp) != NULL ) #endif ) { rp++; ind = 0; *cp = '\0'; if ((rpend - rp) < sizeof(struct timeval)) { (void)printf( "Too little data (%d): %s\n", rpend-rp, cooked); return; } tv.tv_sec = 0; for (i = 0; i < 4; i++) { tv.tv_sec <<= 8; tv.tv_sec |= ((long)*rp++) & 0xff; } tv.tv_usec = 0; for (i = 0; i < 4; i++) { tv.tv_usec <<= 8; tv.tv_usec |= ((long)*rp++) & 0xff; } tvd.tv_sec = tv.tv_sec - lasttv.tv_sec; tvd.tv_usec = tv.tv_usec - lasttv.tv_usec; if (tvd.tv_usec < 0) { tvd.tv_usec += 1000000; tvd.tv_sec--; } (void)printf("%lu.%06lu %lu.%06lu %s\n", tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec, cooked); lasttv = tv; } else { rp++; } } if (ind) { *cp = '\0'; (void)printf("Incomplete data: %s\n", cooked); } } /* * doalarm - send a string out the port, if we have one. */ int doalarm( int fd ) { int n; if (cmd == NULL || cmdlen <= 0) return; n = write(fd, cmd, cmdlen); if (n < 0) { (void) fprintf(stderr, "%s: write(): ", progname); perror(""); } else if (n < cmdlen) { (void) printf("Short write (%d bytes, should be %d)\n", n, cmdlen); } } /* * alarming - receive alarm interupt */ void alarming(void) { wasalarmed = 1; } /* * ioready - handle SIGIO interrupt */ void ioready(void) { iosig = 1; }