1 /*
2 * Changes for use with CM11A copyright 1996, 1997 - 2003 Daniel B. Suthers,
3 * Pleasanton Ca, 94588 USA
4 * E-mail dbs@tanj.com
5 *
6 */
7
8 /*
9 * Copyright 1986 by Larry Campbell, 73 Concord Street, Maynard MA 01754 USA
10 * (maynard!campbell).
11 *
12 * John Chmielewski (tesla!jlc until 9/1/86, then rogue!jlc) assisted
13 * by doing the System V port and adding some nice features. Thanks!
14 */
15
16 /*
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <signal.h>
35 #include <setjmp.h>
36 #if (defined(SCO) || defined (SOLARIS) || defined (ATTSVR4) || defined(OPENBSD) || defined(NETBSD))
37 #include <errno.h>
38 #else
39 #include <sys/errno.h>
40 #endif
41 #include <syslog.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include "x10.h"
45 #if (defined(LINUX) || defined(SOLARIS) || defined(FREEBSD) || defined(DARWIN) || defined(SYSV) || defined(OPENBSD) || defined(NETBSD))
46 #include <string.h> /* char *strerror(); */
47 #endif
48
49 #include <time.h>
50
51 #include "process.h"
52 #include "local.h"
53
54 extern int verbose;
55 extern int i_am_relay, i_am_aux;
56 extern int tty;
57
58 unsigned alarm();
59 void sigtimer( int );
60 #ifdef HAS_ITIMER
61 #include <sys/time.h>
62 #include <unistd.h>
63 struct itimerval iold, icurrent;
64 #endif
65 int xread ( int, unsigned char *, int, int );
66
67 /*
68 * xread(fd, buf, count, timeout)
69 *
70 * Timed read. Works just like read(2) but gives up after
71 * timeout seconds, returning whatever's been read so far.
72 */
73 /* NOTE: The CM11A will pop out a poll message every second when it wants
74 * to send an update. Alarm(1) will go off when the next second starts.
75 * This may be any amount of time up to 1 second. This makes a normal
76 * alarm(1) unsuitable. Thus the use of setitimer. Other OSes will have
77 * similar capabilities that assure a 1 second alarm is actually one second.
78 */
79
80 jmp_buf jb;
81
82
xread(fd,buf,count,timeout)83 int xread(fd, buf, count, timeout)
84 int fd, count, timeout;
85 unsigned char *buf;
86 {
87 static int total; /* so setjump won't clobber it */
88 extern int i_am_relay;
89 int counter;
90 unsigned char *cbuf;
91 char RCSID[]= "@(#) $Id: xread.c,v 1.10 2003/03/17 01:40:32 dbs Exp dbs $\n";
92
93 display(RCSID);
94
95 if (verbose && (! i_am_relay) ) {
96 fprintf(stderr, "xread() called, count=%d, timeout = %d\n", count, timeout);
97 fflush(stderr);
98 }
99
100 total = 0;
101
102 if (setjmp(jb))
103 {
104 if (verbose && (! i_am_relay) ) {
105 fprintf(stderr, "xread() returning %d after timeout\n", total);
106 fflush(stderr);
107 }
108 (void) alarm(0);
109 (void) signal(SIGALRM, SIG_IGN);
110 return (total);
111 }
112
113 /* The compiler would complain that
114 * "argument `buf' and count might be clobbered by `longjmp'"
115 * This is bacause we change them after the setjmp.
116 * To prevent this, we use copies of the arguements.
117 */
118 cbuf = buf;
119 counter = count;
120
121 (void)alarm(0);
122 (void) signal(SIGALRM, sigtimer);
123 #ifdef HAS_ITIMER
124 icurrent.it_interval.tv_sec = 0;
125 icurrent.it_interval.tv_usec = 0;
126 icurrent.it_value.tv_sec = timeout;
127 icurrent.it_value.tv_usec = 30;
128 if (setitimer(ITIMER_REAL, &icurrent, &iold) == -1)
129 if( !i_am_relay )
130 perror ("setitimer");
131 #else
132 (void) alarm((unsigned) timeout);
133 #endif
134
135
136 errno = 0;
137 while (counter--) { /* loop till all characters are read */
138 int i;
139 if ((i = read(fd, (char *)cbuf, 1)) < 1) {
140 if (i == 0) {
141 /* loop around on EOF */
142 counter++; /* reverse the decrement in the while loop. */
143 if( errno == EINTR) /* alarm was triggered */
144 {
145 break;
146 }
147 continue;
148 }
149 if( (i < 0) && (i_am_relay != 1) )
150 perror("read");
151 else
152 if( (i < 0) && (i_am_relay == 1) )
153 {
154 syslog(LOG_ERR,"Relay Xread read error");
155 syslog(LOG_ERR, "%s", strerror(errno));
156 }
157 (void) alarm(0);
158 (void) signal(SIGALRM, SIG_IGN);
159 if (verbose) {
160 fprintf(stderr, "xread() returning %d bytes after error\n", total);
161 fflush(stderr);
162 }
163 return (total);
164 }
165 cbuf++;
166 total++;
167 }
168 (void) alarm(0);
169 (void) signal(SIGALRM, SIG_IGN);
170 if (verbose && (i_am_relay != 1) ) {
171 if ( total == 0 )
172 fprintf(stderr, "xread() returning 0 bytes\n");
173 else
174 fprintf(stderr, "xread() returning %d byte(s). The first is 0x%02x\n", total, buf[0] );
175 fflush(stderr);
176 }
177 return (total);
178 }
179
sigtimer(int signo)180 void sigtimer( int signo )
181 {
182 if (verbose && (! i_am_relay) ){
183 fprintf(stderr, "Alarm - timeout\n");
184 fflush(stderr);
185 }
186 (void) signal(SIGALRM, sigtimer);
187 errno = EINTR;
188 return;
189 /* the jmp temporarily disabled (version 1.34)
190 ... It was causing problems when triggered under linux 2.2.20
191 using USB. The second trap would not behave properly.
192 I don't know why.
193 */
194
195 /* longjmp(jb, 1); */
196 }
197
198
199
200 /* expect xread sends a code to the spool file that specifys how many
201 * incoming characters are to be discarded.
202 * The code is 3 0xff followed by (the number of bytes to expect +127)
203 */
exread(fd,buf,count,timeout)204 int exread(fd, buf, count, timeout)
205 int fd;
206 char *buf;
207 int count;
208 int timeout;
209 {
210 unsigned char lbuf[160];
211 extern int sptty;
212
213 lbuf[1] = lbuf[2] = lbuf[0] = 0xff;
214 lbuf[3] = count+127;
215 if ( (!i_am_relay || i_am_aux) && write(sptty, (char *)lbuf , 4) != 4 )
216 {
217 /* if( i_am_relay )
218 {
219 syslog (LOG_ERR, "exread(): write failed\n");
220 }
221 else */
222
223 if ( !i_am_relay && !i_am_aux )
224 {
225 fprintf (stderr, "exread(): write failed\n");
226 }
227 }
228
229
230 return(xread( fd, (unsigned char *)buf, count, timeout));
231 }
232
233
234
235
is_blocking(int tty)236 int is_blocking ( int tty )
237 {
238 int flags;
239
240 flags = fcntl(tty, F_GETFL);
241
242 if ( flags & O_NONBLOCK )
243 return 0;
244
245 return 1;
246 }
247
file_flags(void)248 int file_flags ( void )
249 {
250 return fcntl(tty, F_GETFL);
251 }
252
setblocking(int fd,int code)253 int setblocking ( int fd, int code )
254 {
255 int flags;
256
257 flags = fcntl(fd, F_GETFL);
258 if ( code == 0 )
259 flags |= O_NONBLOCK;
260 else
261 flags &= ~O_NONBLOCK;
262 fcntl(fd, F_SETFL, flags);
263
264 return flags;
265 }
266
sxread_isr_1(int signo)267 void sxread_isr_1( int signo )
268 {
269 return;
270 }
271
272
273 #if defined(HASSIGACT)
274 /*--------------------------------------------------------+
275 | An interruptable read() like xread(), but from a |
276 | serial port file descriptor. Needs sigaction() |
277 +--------------------------------------------------------*/
sxread(int fd,unsigned char * buffer,int size,int timeout)278 int sxread ( int fd, unsigned char *buffer, int size, int timeout )
279 {
280 extern void cleanup_files();
281 extern void cleanup_aux(void);
282 int count = 0, nread = 0, passes = 0;
283 struct sigaction act;
284
285 if ( fd == TTY_DUMMY ) {
286 sleep(timeout);
287 return 0;
288 }
289
290 errno = 0;
291 setblocking(fd, 1);
292
293 sigaction(SIGALRM, NULL, &act);
294
295 act.sa_handler = sxread_isr_1;
296 act.sa_flags &= ~SA_RESTART;
297
298 sigaction(SIGALRM, &act, NULL);
299
300 alarm(timeout);
301 while ( nread < size && passes++ < 100 ) {
302 count = read(fd, (char *)(buffer + nread), size - nread);
303 if ( count < 0 )
304 break;
305 nread += count;
306 }
307 alarm(0);
308
309 act.sa_handler = SIG_IGN;
310 act.sa_flags |= SA_RESTART;
311 sigaction(SIGALRM, &act, NULL);
312
313 if ( count >= 0 || (errno == EINTR) )
314 return nread;
315
316 syslog(LOG_ERR, "sxread() failed, error = %s\n", strerror(errno));
317
318 if ( i_am_aux )
319 cleanup_aux();
320
321 cleanup_files();
322
323 exit(1);
324
325 return -1;
326 }
327
328
329 #elif defined(HASSIGINT)
330 /*--------------------------------------------------------+
331 | An interruptable read() like xread(), but from a |
332 | serial port file descriptor. Needs siginterrupt() |
333 +--------------------------------------------------------*/
sxread(int fd,unsigned char * buffer,int size,int timeout)334 int sxread ( int fd, unsigned char *buffer, int size, int timeout )
335 {
336 extern void cleanup_files();
337 extern void cleanup_aux(void);
338 int count = 0, nread = 0, passes = 0;
339
340 if ( fd == TTY_DUMMY ) {
341 sleep(timeout);
342 return 0;
343 }
344
345 errno = 0;
346 setblocking(fd, 1);
347 siginterrupt(SIGALRM, 1);
348 signal(SIGALRM, sxread_isr_1);
349 alarm(timeout);
350 while ( size > nread && passes++ < 100 ) {
351 count = read(fd, (char *)(buffer + nread), size - nread);
352 if ( count < 0 )
353 break;
354 nread += count;
355 }
356 alarm(0);
357 siginterrupt(SIGALRM, 0);
358
359 if ( count >= 0 || (count < 0 && errno == EINTR) )
360 return nread;
361
362 syslog(LOG_ERR, "sxread() failed, error = %s\n", strerror(errno));
363
364 if ( i_am_aux )
365 cleanup_aux();
366
367 cleanup_files();
368
369 exit(1);
370
371 return -1;
372 }
373
374
375 #elif defined(SIGKLUGE)
376
377 static int s_fd;
sxread_isr_2(int signo)378 void sxread_isr_2( int signo )
379 {
380 setblocking(s_fd, 0);
381 return;
382 }
383
384 /*--------------------------------------------------------+
385 | An interruptable read() like xread(), but from a |
386 | serial port file descriptor. This one uses a kluge |
387 | whereby the port is changed from blocking to non- |
388 | blocking after the alarm timeout. |
389 +--------------------------------------------------------*/
sxread(int fd,unsigned char * buffer,int size,int timeout)390 int sxread ( int fd, unsigned char *buffer, int size, int timeout )
391 {
392 extern void cleanup_files();
393 extern void cleanup_aux(void);
394 int count = 0, nread = 0, passes = 0;
395
396 if ( fd == TTY_DUMMY ) {
397 sleep(timeout);
398 return 0;
399 }
400
401 s_fd = fd;
402 alarm(0);
403 signal(SIGALRM, sxread_isr_2);
404 alarm(timeout);
405 while ( size > nread && passes++ < 100 ) {
406 errno = 0;
407 setblocking(fd, 1);
408 count = read(fd, (char *)(buffer + nread), size - nread);
409 if ( count < 0 ) {
410 if ( errno == EINTR || errno == EAGAIN ) {
411 break;
412 }
413 else {
414 continue;
415 }
416 }
417 nread += count;
418 }
419 alarm(0);
420 setblocking(fd, 1);
421
422 if ( count >= 0 || (errno == EINTR || errno == EAGAIN) )
423 return nread;
424
425 syslog(LOG_ERR, "sxread() failed, error = %s\n", strerror(errno));
426
427 if ( i_am_aux )
428 cleanup_aux();
429
430 cleanup_files();
431
432 exit(1);
433
434 return -1;
435 }
436
437 #else
438 /*--------------------------------------------------------+
439 | This version of sxread polls until the characters are |
440 | read or timeout. Timeout is not very accurate - can |
441 | take twice as long as specified with older kernels. |
442 +--------------------------------------------------------*/
sxread(int fd,unsigned char * buffer,int size,int timeout)443 int sxread ( int fd, unsigned char *buffer, int size, int timeout )
444 {
445 extern void cleanup_files();
446 extern void cleanup_aux();
447 int count = 0, nread = 0, passes = 0;
448
449 if ( fd == TTY_DUMMY ) {
450 sleep(timeout);
451 return 0;
452 }
453
454 setblocking(fd, 0);
455 passes = 100 * timeout;
456 while ( size > nread && --passes > 0 ) {
457 errno = 0;
458 count = read(fd, (char *)(buffer + nread), size - nread);
459 if ( count <= 0 ) {
460 millisleep(10);
461 continue;
462 }
463 nread += count;
464 }
465 setblocking(fd, 1);
466
467 if ( count >= 0 || errno == EAGAIN )
468 return nread;
469
470 syslog(LOG_ERR, "sxread() failed, error = %s\n", strerror(errno));
471
472 if ( i_am_aux )
473 cleanup_aux();
474
475 cleanup_files();
476
477 exit(1);
478
479 return -1;
480 }
481
482 #endif
483
484
485 #if 0
486 int timeout_flag = 0;
487
488 void xread_sigtimer ( int signo )
489 {
490 timeout_flag = 1;
491 errno = EINTR;
492 return;
493 }
494
495 /*
496 * An experimental version of xread()
497 */
498 int xread ( int fd, unsigned char *buffer, int count, int timeout )
499 {
500 int nread, ntot = 0;
501
502 if ( fd == TTY_DUMMY ) {
503 sleep(timeout);
504 return 0;
505 }
506
507 if ( verbose && (! i_am_relay) ) {
508 fprintf(stderr, "xread() called, count=%d, timeout = %d\n", count, timeout);
509 fflush(stderr);
510 }
511
512 timeout_flag = 0;
513
514 (void)alarm(0);
515 (void) signal(SIGALRM, xread_sigtimer);
516 #ifdef HAS_ITIMER
517 icurrent.it_interval.tv_sec = 0;
518 icurrent.it_interval.tv_usec = 0;
519 icurrent.it_value.tv_sec = timeout;
520 icurrent.it_value.tv_usec = 30;
521 if ( setitimer(ITIMER_REAL, &icurrent, &iold) == -1 ) {
522 if( !i_am_relay )
523 perror ("setitimer");
524 }
525 #else
526 (void) alarm((unsigned) timeout);
527 #endif
528
529 errno = 0;
530 while ( ntot < count && timeout_flag == 0 ) {
531 nread = read(fd, (char *)(buffer + ntot), count - ntot);
532 if ( nread < 0 ) {
533 syslog(LOG_ERR, "xread: read() error %s\n", strerror(errno));
534 if ( verbose && !i_am_relay ) {
535 fprintf(stderr, "xread() returning %d bytes after error\n", ntot);
536 fflush(stderr);
537 }
538 alarm(0);
539 signal(SIGALRM, SIG_IGN);
540 return ntot;
541 }
542 ntot += nread;
543
544 if ( nread == 0 )
545 millisleep(10);
546 }
547
548 if ( verbose && !i_am_relay ) {
549 if ( ntot == 0 )
550 fprintf(stderr, "xread() returning 0 bytes\n");
551 else
552 fprintf(stderr, "xread() returning %d byte(s). The first is 0x%02x\n", ntot, buffer[0]);
553 fflush(stderr);
554 }
555 alarm(0);
556 signal(SIGALRM, SIG_IGN);
557
558 return ntot;
559 }
560 #endif
561
562
563 #if 0
564 /*
565 * This is an alternate experimental version of xread which does not use
566 * a signal for timeout.
567 */
568 int xread ( int fd, unsigned char *buffer, int count, int timeout )
569 {
570 int nread, ntot = 0;
571 long maxpasses, passes = 0;
572 time_t tquit;
573
574 if ( fd == TTY_DUMMY ) {
575 sleep(timeout);
576 return 0;
577 }
578
579 if ( verbose && (! i_am_relay) ) {
580 fprintf(stderr, "xread() called, count=%d, timeout = %d\n", count, timeout);
581 fflush(stderr);
582 }
583
584 maxpasses = timeout * 100; /* at nominal 10 msec/pass */
585
586 /* System clock is checked since the timing resolution with older kernels */
587 /* is such that the timout interval could otherwise be twice as long as */
588 /* specified */
589
590 tquit = time(NULL) + (time_t)(timeout + 1);
591
592 errno = 0;
593 while ( ntot < count && passes < maxpasses && time(NULL) < tquit ) {
594 nread = read(fd, (char *)(buffer + ntot), count - ntot);
595 if ( nread < 0 ) {
596 syslog(LOG_ERR, "xread: read() error %s\n", strerror(errno));
597 if ( verbose ) {
598 fprintf(stderr, "xread() returning %d bytes after error\n", ntot);
599 fflush(stderr);
600 }
601 return ntot;
602 }
603 ntot += nread;
604 passes++;
605 if ( nread == 0 )
606 millisleep(10);
607 }
608
609 if ( verbose && (i_am_relay != 1) ) {
610 if ( ntot == 0 )
611 fprintf(stderr, "xread() returning 0 bytes\n");
612 else
613 fprintf(stderr, "xread() returning %d byte(s). The first is 0x%02x\n", ntot, buffer[0]);
614 fflush(stderr);
615 }
616
617 return ntot;
618 }
619
620 #endif
621
622
623
624
625
626
627
628
629
630
631
632