]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/clockstuff/clktest.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 "clktest-opts.h"
8
9 #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
10
11 #if defined(ULT_2_0_SUCKS)
12 #ifndef sigmask
13 #define sigmask(m)      (1<<(m))
14 #endif
15 #endif
16
17 #ifndef STREAM
18 # ifndef CLKLDISC
19     CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM;
20 # endif
21 #else
22 # ifdef CLKLDISC
23     ONLY_ONE_CLOCK_LINE_DISCIPLINE_FOR_THIS_PROGRAM;
24 # endif
25 #endif
26
27 /*
28  * Mask for blocking SIGIO and SIGALRM
29  */
30 #define BLOCKSIGMASK    (sigmask(SIGIO)|sigmask(SIGALRM))
31
32 #define progname clktestOptions.pzProgName
33
34 struct timeval timeout = { 0 };
35 char *cmd = NULL;
36 int cmdlen;
37
38 #ifdef CLKLDISC
39 u_long magic1 = DEFMAGIC;
40 u_long magic2 = DEFMAGIC;
41 #endif
42
43 int speed = B9600;
44 int ttflags = RAW|EVENP|ODDP;
45
46 volatile int wasalarmed;
47 volatile int iosig;
48
49 struct timeval lasttv;
50
51 extern u_long ustotslo[];
52 extern u_long ustotsmid[];
53 extern u_long ustotshi[];
54
55 int alarming();
56 int ioready();
57
58 /*
59  * main - parse arguments and handle options
60  */
61 int
62 main(
63         int argc,
64         char *argv[]
65         )
66 {
67         int fd;
68         struct sgttyb ttyb;
69         struct itimerval itimer;
70
71 #ifdef STREAM
72         magic[0] = 0;
73 #endif
74
75         {
76             int ct = optionProcess( &clktestOptions, argc, argv );
77             if (HAVE_OPT(COMMAND) && (strlen(OPT_ARG(COMMAND)) == 0)) {
78                 fputs( "The command option string must not be empty\n", stderr );
79                 USAGE( EXIT_FAILURE );
80             }
81
82             if ((argc -= ct) != 1) {
83                 fputs( "Missing tty device name\n", stderr );
84                 USAGE( EXIT_FAILURE );
85             }
86             argv += ct;
87         }
88 #ifdef STREAM
89         if (!strlen(magic))
90             strcpy(magic,DEFMAGIC);
91 #endif
92
93         fd = open(*argv, HAVE_OPT(TIMEOUT) ? O_RDWR : O_RDONLY, 0777);
94         if (fd == -1) {
95                 fprintf(stderr, "%s: open(%s): ", progname, *argv);
96                 perror("");
97                 exit(1);
98         }
99
100         if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
101                 (void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname);
102                 perror("");
103                 exit(1);
104         }
105
106         /*
107          * If we have the clock discipline, set the port to raw.  Otherwise
108          * we run cooked.
109          */
110         ttyb.sg_ispeed = ttyb.sg_ospeed = speed;
111 #ifdef CLKLDISC
112         ttyb.sg_erase = (char)magic1;
113         ttyb.sg_kill = (char)magic2;
114 #endif
115         ttyb.sg_flags = (short)ttflags;
116         if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
117                 (void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname);
118                 perror("");
119                 exit(1);
120         }
121
122         if (fcntl(fd, F_SETOWN, getpid()) == -1) {
123                 (void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname);
124                 perror("");
125                 exit(1);
126         }
127
128 #ifdef CLKLDISC
129         {
130                 int ldisc;
131                 ldisc = CLKLDISC;
132                 if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
133                         (void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname);
134                         perror("");
135                         exit(1);
136                 }
137         }
138 #endif
139 #ifdef STREAM
140         if (ioctl(fd, I_POP, 0) >=0 ) ;
141         if (ioctl(fd, I_PUSH, "clk") < 0) {
142                 (void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname);
143                 perror("");
144                 exit(1);
145         }
146         if (ioctl(fd, CLK_SETSTR, magic) < 0) {
147                 (void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname);
148                 perror("");
149                 exit(1);
150         }
151 #endif
152
153
154         (void) gettimeofday(&lasttv, (struct timezone *)0);
155         if (HAVE_OPT(TIMEOUT)) {
156                 /*
157                  * set non-blocking, async I/O on the descriptor
158                  */
159                 iosig = 0;
160                 (void) signal(SIGIO, ioready);
161                 if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
162                         (void) fprintf(stderr, "%s: fcntl(F_SETFL): ",
163                                        progname);
164                         perror("");
165                         exit(1);
166                 }
167
168                 /*
169                  * Set up the alarm interrupt.
170                  */
171                 wasalarmed = 0;
172                 (void) signal(SIGALRM, alarming);
173                 timeout.tv_sec = OPT_VALUE_TIMEOUT;
174                 itimer.it_interval = itimer.it_value = timeout;
175                 setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
176                 doboth(fd);
177         }
178         doioonly(fd);
179 }
180
181
182 /*
183  * doboth - handle both I/O and alarms via SIGIO
184  */
185 int
186 doboth(
187         int fd
188         )
189 {
190         int n;
191         int sawalarm;
192         int sawiosig;
193         int omask;
194         fd_set fds;
195         struct timeval tvzero;
196
197         sawalarm = 0;
198         sawiosig = 0;
199         FD_ZERO(&fds);
200         for (;;) {
201                 omask = sigblock(BLOCKSIGMASK);
202                 if (wasalarmed) {               /* alarmed? */
203                         sawalarm = 1;
204                         wasalarmed = 0;
205                 }
206                 if (iosig) {
207                         sawiosig = 1;
208                         iosig = 0;
209                 }
210
211                 if (!sawalarm && !sawiosig) {
212                         /*
213                          * Nothing to do.  Wait for something.
214                          */
215                         sigpause(omask);
216                         if (wasalarmed) {               /* alarmed? */
217                                 sawalarm = 1;
218                                 wasalarmed = 0;
219                         }
220                         if (iosig) {
221                                 sawiosig = 1;
222                                 iosig = 0;
223                         }
224                 }
225                 (void)sigsetmask(omask);
226
227                 if (sawiosig) {
228
229                         do {
230                                 tvzero.tv_sec = tvzero.tv_usec = 0;
231                                 FD_SET(fd, &fds);
232                                 n = select(fd+1, &fds, (fd_set *)0,
233                                            (fd_set *)0, &tvzero);
234                                 if (n > 0)
235                                     doio(fd);
236                         } while (n > 0);
237
238                         if (n == -1) {
239                                 (void) fprintf(stderr, "%s: select: ",
240                                                progname);
241                                 perror("");
242                                 exit(1);
243                         }
244                         sawiosig = 0;
245                 }
246                 if (sawalarm) {
247                         doalarm(fd);
248                         sawalarm = 0;
249                 }
250         }
251 }
252
253
254 /*
255  * doioonly - do I/O.  This avoids the use of signals
256  */
257 int
258 doioonly(
259         int fd
260         )
261 {
262         int n;
263         fd_set fds;
264
265         FD_ZERO(&fds);
266         for (;;) {
267                 FD_SET(fd, &fds);
268                 n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0,
269                            (struct timeval *)0);
270                 if (n > 0)
271                     doio(fd);
272         }
273 }
274
275
276 /*
277  * doio - read a buffer full of stuff and print it out
278  */
279 int
280 doio(
281         int fd
282         )
283 {
284         register char *rp, *rpend;
285         register char *cp;
286         register int i;
287         char raw[512];
288         struct timeval tv, tvd;
289         int rlen;
290         int ind;
291         char cooked[2049];
292         static char *digits = "0123456789abcdef";
293
294         rlen = read(fd, raw, sizeof(raw));
295         if (rlen < 0) {
296                 (void) fprintf(stderr, "%s: read(): ", progname);
297                 perror("");
298                 return;
299         }
300         if (rlen == 0) {
301                 (void) printf("Zero length read\n");
302                 return;
303         }
304
305         cp = cooked;
306         rp = raw;
307         rpend = &raw[rlen];
308         ind = 0;
309
310         while (rp < rpend) {
311                 ind = 1;
312                 if (isprint(*rp))
313                     *cp++ = *rp;
314                 else {
315                         *cp++ = '<';
316                         *cp++ = digits[((*rp)>>4) & 0xf];
317                         *cp++ = digits[*rp & 0xf];
318                         *cp++ = '>';
319                 }
320                 if (
321 #ifdef CLKLDISC
322                         (*rp == (char)magic1 || *rp == (char)magic2)
323 #else
324                         ( strchr( magic, *rp) != NULL )
325 #endif
326                         ) {
327                         rp++;
328                         ind = 0;
329                         *cp = '\0';
330                         if ((rpend - rp) < sizeof(struct timeval)) {
331                                 (void)printf(
332                                         "Too little data (%d): %s\n",
333                                         rpend-rp, cooked);
334                                 return;
335                         }
336
337                         tv.tv_sec = 0;
338                         for (i = 0; i < 4; i++) {
339                                 tv.tv_sec <<= 8;
340                                 tv.tv_sec |= ((long)*rp++) & 0xff;
341                         }
342                         tv.tv_usec = 0;
343                         for (i = 0; i < 4; i++) {
344                                 tv.tv_usec <<= 8;
345                                 tv.tv_usec |= ((long)*rp++) & 0xff;
346                         }
347
348                         tvd.tv_sec = tv.tv_sec - lasttv.tv_sec;
349                         tvd.tv_usec = tv.tv_usec - lasttv.tv_usec;
350                         if (tvd.tv_usec < 0) {
351                                 tvd.tv_usec += 1000000;
352                                 tvd.tv_sec--;
353                         }
354
355                         (void)printf("%lu.%06lu %lu.%06lu %s\n",
356                                      tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec,
357                                      cooked);
358                         lasttv = tv;
359                 } else {
360                         rp++;
361                 }
362         }
363
364         if (ind) {
365                 *cp = '\0';
366                 (void)printf("Incomplete data: %s\n", cooked);
367         }
368 }
369
370
371 /*
372  * doalarm - send a string out the port, if we have one.
373  */
374 int
375 doalarm(
376         int fd
377         )
378 {
379         int n;
380
381         if (! HAVE_OPT(COMMAND))
382             return;
383
384         n = write(fd, cmd, cmdlen);
385
386         if (n < 0) {
387                 (void) fprintf(stderr, "%s: write(): ", progname);
388                 perror("");
389         } else if (n < cmdlen) {
390                 (void) printf("Short write (%d bytes, should be %d)\n",
391                               n, cmdlen);
392         }
393 }
394
395
396 /*
397  * alarming - receive alarm interupt
398  */
399 void
400 alarming(void)
401 {
402         wasalarmed = 1;
403 }
404
405 /*
406  * ioready - handle SIGIO interrupt
407  */
408 void
409 ioready(void)
410 {
411         iosig = 1;
412 }