Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / ntp / clockstuff / clktest.c
1 /* clktest.c,v 3.1 1993/07/06 01:05:23 jbj Exp
2  * clktest - test the clock line discipline
3  *
4  * usage: clktest -b bps -f -t timeo -s cmd -c char1 -a char2 /dev/whatever
5  */
6
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <signal.h>
12 #include <netinet/in.h>
13 #include <sys/ioctl.h>
14 #include <sys/time.h>
15 #include <sys/file.h>
16 #include <sgtty.h>
17
18 #include "../include/ntp_fp.h"
19 #include "../include/ntp.h"
20 #include "../include/ntp_unixtime.h"
21
22 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
23
24 #if defined(ULT_2_0_SUCKS)
25 #ifndef sigmask
26 #define sigmask(m)      (1<<(m))
27 #endif
28 #endif
29
30 #ifndef STREAM
31 #ifndef CLKLDISC
32 CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM;
33 #endif
34 #endif
35
36 /*
37  * Mask for blocking SIGIO and SIGALRM
38  */
39 #define BLOCKSIGMASK    (sigmask(SIGIO)|sigmask(SIGALRM))
40
41 /*
42  * speed table
43  */
44 struct speeds {
45         int bps;
46         int rate;
47 } speedtab[] = {
48         { 300,          B300 },
49         { 1200,         B1200 },
50         { 2400,         B2400 },
51         { 4800,         B4800 },
52         { 9600,         B9600 },
53         { 19200,        EXTA },
54         { 38400,        EXTB },
55         { 0,            0 }
56 };
57
58 char *progname;
59 int debug;
60
61 #ifdef CLKLDISC
62 #define DEFMAGIC        '\r'
63 #endif
64
65 #ifdef CLKLDISC
66 # ifdef STREAM
67 #  include <stropts.h>
68 #  ifdef HAVE_SYS_CLKDEFS_H
69 #   include <sys/clkdefs.h>
70 #  endif
71 #  define DEFMAGIC      "\r"
72 # endif
73 #endif
74  
75 struct timeval timeout = { 0 };
76 char *cmd = NULL;
77 int cmdlen;
78 int docmd = 0;
79 #ifdef CLKLDISC
80 u_long magic1 = DEFMAGIC;
81 u_long magic2 = DEFMAGIC;
82 #endif
83 #ifdef STREAM
84 char magic[32];
85 #endif
86 int speed = B9600;
87 int ttflags = RAW|EVENP|ODDP;
88
89 volatile int wasalarmed;
90 volatile int iosig;
91
92 struct timeval lasttv;
93
94 extern u_long ustotslo[];
95 extern u_long ustotsmid[];
96 extern u_long ustotshi[];
97
98 /*
99  * main - parse arguments and handle options
100  */
101 int
102 main(
103         int argc,
104         char *argv[]
105         )
106 {
107         int c;
108         int errflg = 0;
109         struct speeds *spd;
110         u_long tmp;
111         int fd;
112         struct sgttyb ttyb;
113         struct itimerval itimer;
114         extern int ntp_optind;
115         extern char *ntp_optarg;
116         int alarming();
117         int ioready();
118
119         progname = argv[0];
120 #ifdef STREAM
121         magic[0] = 0;
122 #endif
123         while ((c = ntp_getopt(argc, argv, "a:b:c:dfs:t:")) != EOF)
124             switch (c) {
125 #ifdef CLKLDISC
126                 case 'a':
127 #endif
128                 case 'c':
129                     if (!atouint(ntp_optarg, &tmp)) {
130                             (void) fprintf(stderr,
131                                            "%s: argument for -%c must be integer\n",
132                                            progname, c);
133                             errflg++;
134                             break;
135                     }
136 #ifdef CLKLDISC
137                     if (c == 'c')
138                         magic1 = tmp;
139                     else
140                         magic2 = tmp;
141 #endif
142 #ifdef STREAM
143                     magic[strlen(magic)+1] = '\0';
144                     magic[strlen(magic)] = tmp;
145 #endif
146                     break;
147                 case 'b':
148                     if (!atouint(ntp_optarg, &tmp)) {
149                             errflg++;
150                             break;
151                     }
152                     spd = speedtab;
153                     while (spd->bps != 0)
154                         if ((int)tmp == spd->bps)
155                             break;
156                     if (spd->bps == 0) {
157                             (void) fprintf(stderr,
158                                            "%s: speed %lu is unsupported\n",
159                                            progname, tmp);
160                             errflg++;
161                     } else {
162                             speed = spd->rate;
163                     }
164                     break;
165                 case 'd':
166                     ++debug;
167                     break;
168                 case 'f':
169                     ttflags |= CRMOD;
170                     break;
171                 case 's':
172                     cmdlen = strlen(ntp_optarg);
173                     if (cmdlen == 0)
174                         errflg++;
175                     else
176                         cmd = ntp_optarg;
177                     break;
178                 case 't':
179                     if (!atouint(ntp_optarg, &tmp))
180                         errflg++;
181                     else {
182                             timeout.tv_sec = (long)tmp;
183                             docmd = 1;
184                     }
185                     break;
186                 default:
187                     errflg++;
188                     break;
189             }
190         if (errflg || ntp_optind+1 != argc) {
191                 (void) fprintf(stderr,
192 #ifdef CLKLDISC
193                                "usage: %s [-b bps] [-c magic1] [-a magic2] [-f] [-s cmd] [-t timeo]  tty_device\n",
194 #endif
195 #ifdef STREAM
196                                "usage: %s [-b bps] [-c magic1] [-c magic2]... [-f] [-s cmd] [-t timeo]  tty_device\n",
197 #endif
198                                progname);
199                 exit(2);
200         }
201
202 #ifdef STREAM
203         if (!strlen(magic))
204             strcpy(magic,DEFMAGIC);
205 #endif
206
207         if (docmd)
208             fd = open(argv[ntp_optind], O_RDWR, 0777);
209         else
210             fd = open(argv[ntp_optind], O_RDONLY, 0777);
211         if (fd == -1) {
212                 (void) fprintf(stderr, "%s: open(%s): ", progname,
213                                argv[ntp_optind]);
214                 perror("");
215                 exit(1);
216         }
217
218         if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
219                 (void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname);
220                 perror("");
221                 exit(1);
222         }
223
224         /*
225          * If we have the clock discipline, set the port to raw.  Otherwise
226          * we run cooked.
227          */
228         ttyb.sg_ispeed = ttyb.sg_ospeed = speed;
229 #ifdef CLKLDISC
230         ttyb.sg_erase = (char)magic1;
231         ttyb.sg_kill = (char)magic2;
232 #endif
233         ttyb.sg_flags = (short)ttflags;
234         if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
235                 (void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname);
236                 perror("");
237                 exit(1);
238         }
239
240         if (fcntl(fd, F_SETOWN, getpid()) == -1) {
241                 (void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname);
242                 perror("");
243                 exit(1);
244         }
245
246 #ifdef CLKLDISC
247         {
248                 int ldisc;
249                 ldisc = CLKLDISC;
250                 if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
251                         (void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname);
252                         perror("");
253                         exit(1);
254                 }
255         }
256 #endif
257 #ifdef STREAM
258         if (ioctl(fd, I_POP, 0) >=0 ) ;
259         if (ioctl(fd, I_PUSH, "clk") < 0) {
260                 (void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname);
261                 perror("");
262                 exit(1);
263         }
264         if (ioctl(fd, CLK_SETSTR, magic) < 0) {
265                 (void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname);
266                 perror("");
267                 exit(1);
268         }
269 #endif
270
271
272         (void) gettimeofday(&lasttv, (struct timezone *)0);
273         if (docmd) {
274                 /*
275                  * set non-blocking, async I/O on the descriptor
276                  */
277                 iosig = 0;
278                 (void) signal(SIGIO, ioready);
279                 if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
280                         (void) fprintf(stderr, "%s: fcntl(F_SETFL): ",
281                                        progname);
282                         perror("");
283                         exit(1);
284                 }
285
286                 /*
287                  * Set up the alarm interrupt.
288                  */
289                 wasalarmed = 0;
290                 (void) signal(SIGALRM, alarming);
291                 itimer.it_interval = itimer.it_value = timeout;
292                 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
293                 doboth(fd);
294         }
295         doioonly(fd);
296 }
297
298
299 /*
300  * doboth - handle both I/O and alarms via SIGIO
301  */
302 int
303 doboth(
304         int fd
305         )
306 {
307         int n;
308         int sawalarm;
309         int sawiosig;
310         int omask;
311         fd_set fds;
312         struct timeval tvzero;
313
314         sawalarm = 0;
315         sawiosig = 0;
316         FD_ZERO(&fds);
317         for (;;) {
318                 omask = sigblock(BLOCKSIGMASK);
319                 if (wasalarmed) {               /* alarmed? */
320                         sawalarm = 1;
321                         wasalarmed = 0;
322                 }
323                 if (iosig) {
324                         sawiosig = 1;
325                         iosig = 0;
326                 }
327
328                 if (!sawalarm && !sawiosig) {
329                         /*
330                          * Nothing to do.  Wait for something.
331                          */
332                         sigpause(omask);
333                         if (wasalarmed) {               /* alarmed? */
334                                 sawalarm = 1;
335                                 wasalarmed = 0;
336                         }
337                         if (iosig) {
338                                 sawiosig = 1;
339                                 iosig = 0;
340                         }
341                 }
342                 (void)sigsetmask(omask);
343
344                 if (sawiosig) {
345
346                         do {
347                                 tvzero.tv_sec = tvzero.tv_usec = 0;
348                                 FD_SET(fd, &fds);
349                                 n = select(fd+1, &fds, (fd_set *)0,
350                                            (fd_set *)0, &tvzero);
351                                 if (n > 0)
352                                     doio(fd);
353                         } while (n > 0);
354
355                         if (n == -1) {
356                                 (void) fprintf(stderr, "%s: select: ",
357                                                progname);
358                                 perror("");
359                                 exit(1);
360                         }
361                         sawiosig = 0;
362                 }
363                 if (sawalarm) {
364                         doalarm(fd);
365                         sawalarm = 0;
366                 }
367         }
368 }
369
370
371 /*
372  * doioonly - do I/O.  This avoids the use of signals
373  */
374 int
375 doioonly(
376         int fd
377         )
378 {
379         int n;
380         fd_set fds;
381
382         FD_ZERO(&fds);
383         for (;;) {
384                 FD_SET(fd, &fds);
385                 n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0,
386                            (struct timeval *)0);
387                 if (n > 0)
388                     doio(fd);
389         }
390 }
391
392
393 /*
394  * doio - read a buffer full of stuff and print it out
395  */
396 int
397 doio(
398         int fd
399         )
400 {
401         register char *rp, *rpend;
402         register char *cp;
403         register int i;
404         char raw[512];
405         struct timeval tv, tvd;
406         int rlen;
407         int ind;
408         char cooked[2049];
409         static char *digits = "0123456789abcdef";
410
411         rlen = read(fd, raw, sizeof(raw));
412         if (rlen < 0) {
413                 (void) fprintf(stderr, "%s: read(): ", progname);
414                 perror("");
415                 return;
416         }
417         if (rlen == 0) {
418                 (void) printf("Zero length read\n");
419                 return;
420         }
421
422         cp = cooked;
423         rp = raw;
424         rpend = &raw[rlen];
425         ind = 0;
426
427         while (rp < rpend) {
428                 ind = 1;
429                 if (isprint(*rp))
430                     *cp++ = *rp;
431                 else {
432                         *cp++ = '<';
433                         *cp++ = digits[((*rp)>>4) & 0xf];
434                         *cp++ = digits[*rp & 0xf];
435                         *cp++ = '>';
436                 }
437                 if (
438 #ifdef CLKLDISC
439                         (*rp == (char)magic1 || *rp == (char)magic2)
440 #else
441                         ( strchr( magic, *rp) != NULL )
442 #endif
443                         ) {
444                         rp++;
445                         ind = 0;
446                         *cp = '\0';
447                         if ((rpend - rp) < sizeof(struct timeval)) {
448                                 (void)printf(
449                                         "Too little data (%d): %s\n",
450                                         rpend-rp, cooked);
451                                 return;
452                         }
453
454                         tv.tv_sec = 0;
455                         for (i = 0; i < 4; i++) {
456                                 tv.tv_sec <<= 8;
457                                 tv.tv_sec |= ((long)*rp++) & 0xff;
458                         }
459                         tv.tv_usec = 0;
460                         for (i = 0; i < 4; i++) {
461                                 tv.tv_usec <<= 8;
462                                 tv.tv_usec |= ((long)*rp++) & 0xff;
463                         }
464
465                         tvd.tv_sec = tv.tv_sec - lasttv.tv_sec;
466                         tvd.tv_usec = tv.tv_usec - lasttv.tv_usec;
467                         if (tvd.tv_usec < 0) {
468                                 tvd.tv_usec += 1000000;
469                                 tvd.tv_sec--;
470                         }
471
472                         (void)printf("%lu.%06lu %lu.%06lu %s\n",
473                                      tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec,
474                                      cooked);
475                         lasttv = tv;
476                 } else {
477                         rp++;
478                 }
479         }
480
481         if (ind) {
482                 *cp = '\0';
483                 (void)printf("Incomplete data: %s\n", cooked);
484         }
485 }
486
487
488 /*
489  * doalarm - send a string out the port, if we have one.
490  */
491 int
492 doalarm(
493         int fd
494         )
495 {
496         int n;
497
498         if (cmd == NULL || cmdlen <= 0)
499             return;
500
501         n = write(fd, cmd, cmdlen);
502
503         if (n < 0) {
504                 (void) fprintf(stderr, "%s: write(): ", progname);
505                 perror("");
506         } else if (n < cmdlen) {
507                 (void) printf("Short write (%d bytes, should be %d)\n",
508                               n, cmdlen);
509         }
510 }
511
512
513 /*
514  * alarming - receive alarm interupt
515  */
516 void
517 alarming(void)
518 {
519         wasalarmed = 1;
520 }
521
522 /*
523  * ioready - handle SIGIO interrupt
524  */
525 void
526 ioready(void)
527 {
528         iosig = 1;
529 }