1 /* -*- mode: c; mode: fold -*- */
2 /*{{{ includes */
3 # include "config.h"
4 # include <stdio.h>
5 # include <stdlib.h>
6 # include <stdarg.h>
7 # include <ctype.h>
8 # include <unistd.h>
9 # include <fcntl.h>
10 # include <string.h>
11 # include <termios.h>
12 # include <errno.h>
13 # include <signal.h>
14 # include <sys/time.h>
15 # include <sys/types.h>
16 # include <sys/stat.h>
17 # if HAVE_SYS_SELECT_H
18 # include <sys/select.h>
19 # endif /* HAVE_SYS_SELECT_H */
20 # if HAVE_SYS_SYSMACROS_H
21 # include <sys/sysmacros.h>
22 # elif HAVE_SYS_MKDEV_H
23 # include <sys/mkdev.h>
24 # else /* ! HAVE_SYS_SYSMACROS_H && ! HAVE_SYS_MKDEV_H */
25 # ifndef major
26 # define major(xx) (((xx) >> 8) & 0xff)
27 # define minor(xx) ((xx) & 0xff)
28 # endif /* major */
29 # endif /* HAVE_SYS_SYSMACROS_H || HAVE_SYS_MKDEV_H */
30 # include "pager.h"
31 /*}}}*/
32 /*{{{ statics and typedefs */
33 static struct {
34 int speed;
35 speed_t tok;
36 } stab[] = {
37 { 300, B300 },
38 { 1200, B1200 },
39 { 2400, B2400 },
40 { 4800, B4800 },
41 { 9600, B9600 },
42 { 19200, B19200 },
43 { 38400, B38400 },
44 # ifdef B57600
45 { 57600, B57600 },
46 # endif /* B57600 */
47 # ifdef B115200
48 { 115200, B115200 },
49 # endif /* B115200 */
50 # ifdef B230400
51 { 230400, B230400 },
52 # endif /* B230400 */
53 # ifdef B460800
54 { 460800, B460800 },
55 # endif /* B460800 */
56 { -1, B9600 }
57 };
58
59 static char *lckmth[] = {
60 "ascii",
61 "binary",
62 "lower",
63 "upper",
64 "sysv4",
65 "timeout",
66 NULL
67 };
68
69 typedef struct {
70 # ifndef NDEBUG
71 # define MAGIC MKMAGIC ('t', 't', 'y', '\0')
72 long magic;
73 # endif /* NDEBUG */
74 char *lck;
75 char *device;
76 struct termios tty, sav;
77 int fd;
78 string_t *line;
79 char *sep;
80 void (*callback) (void *, string_t *, char_t, void *);
81 void *data;
82 Bool suspend;
83 } serial;
84
85 typedef struct _expect {
86 int idx;
87 char *str;
88 int pos;
89 int len;
90 struct _expect
91 *next;
92 } expect;
93 /*}}}*/
94 /*{{{ support routines */
95 static char *
mkprint(char * str,int len)96 mkprint (char *str, int len)
97 {
98 static char *buf = NULL;
99 static int size = 0;
100 int n;
101 char ch;
102 char extra;
103 char *ptr;
104
105 if (len >= size) {
106 size = len + 128;
107 if (! (buf = Realloc (buf, size + 2)))
108 return NULL;
109 }
110 extra = '\0';
111 for (n = 0; len > 0; ++str, --len) {
112 if (n + 8 >= size) {
113 size += 128;
114 if (! (buf = Realloc (buf, size + 2)))
115 break;
116 }
117 ch = *str;
118 if (ch & 0x80) {
119 buf[n++] = '<';
120 buf[n++] = 'M';
121 buf[n++] = '-';
122 ch &= 0x7f;
123 extra = '>';
124 }
125 switch (ch) {
126 case '\x00': ptr = "<nul>"; break;
127 case '\x01': ptr = "<soh>"; break;
128 case '\x02': ptr = "<stx>"; break;
129 case '\x03': ptr = "<etx>"; break;
130 case '\x04': ptr = "<eot>"; break;
131 case '\x05': ptr = "<enq>"; break;
132 case '\x06': ptr = "<ack>"; break;
133 case '\x07': ptr = "<bel>"; break;
134 case '\x08': ptr = "<bs>"; break;
135 case '\x09': ptr = "<ht>"; break;
136 case '\x0a': ptr = "<lf>"; break;
137 case '\x0b': ptr = "<vt>"; break;
138 case '\x0c': ptr = "<ff>"; break;
139 case '\x0d': ptr = "<cr>"; break;
140 case '\x0e': ptr = "<so>"; break;
141 case '\x0f': ptr = "<si>"; break;
142 case '\x10': ptr = "<dle>"; break;
143 case '\x11': ptr = "<dc1>"; break;
144 case '\x12': ptr = "<dc2>"; break;
145 case '\x13': ptr = "<dc3>"; break;
146 case '\x14': ptr = "<dc4>"; break;
147 case '\x15': ptr = "<nak>"; break;
148 case '\x16': ptr = "<syn>"; break;
149 case '\x17': ptr = "<etb>"; break;
150 case '\x18': ptr = "<can>"; break;
151 case '\x19': ptr = "<em>"; break;
152 case '\x1a': ptr = "<sub>"; break;
153 case '\x1b': ptr = "<esc>"; break;
154 case '\x1c': ptr = "<fs>"; break;
155 case '\x1d': ptr = "<gs>"; break;
156 case '\x1e': ptr = "<rs>"; break;
157 case '\x1f': ptr = "<us>"; break;
158 case '\x7f': ptr = "<del>"; break;
159 default:
160 ptr = NULL;
161 buf[n++] = ch;
162 break;
163 }
164 if (ptr)
165 while (*ptr)
166 buf[n++] = *ptr++;
167 if (extra) {
168 buf[n++] = extra;
169 extra = '\0';
170 }
171 }
172 if (buf)
173 buf[n] = '\0';
174 return buf;
175 }
176
177 static inline void
msleep(int msec)178 msleep (int msec)
179 {
180 struct timeval tv;
181
182 if (msec > 0) {
183 do {
184 tv.tv_sec = msec / 1000;
185 tv.tv_usec = (msec % 1000) * 1000;
186 errno = 0;
187 } while ((select (0, NULL, NULL, NULL, & tv) < 0) && (errno == EINTR));
188 }
189 }
190
191 static inline int
data_ready(int fd,int * msec)192 data_ready (int fd, int *msec)
193 {
194 int ret = 0;
195 struct timeval tv;
196 fd_set fset;
197
198 FD_ZERO (& fset);
199 FD_SET (fd, & fset);
200 tv.tv_sec = *msec / 1000;
201 tv.tv_usec = (*msec % 1000) * 1000;
202 if (((ret = select (fd + 1, & fset, NULL, NULL, & tv)) > 0) && FD_ISSET (fd, & fset)) {
203 *msec = tv.tv_sec * 1000 + (tv.tv_usec / 1000);
204 return 1;
205 }
206 return ret;
207 }
208
209 static Bool
do_lock(serial * s,char * dev,char * prefix,char * method)210 do_lock (serial *s, char *dev, char *prefix, char *method)
211 {
212 Bool binary;
213 Bool lower, upper;
214 Bool sysv4;
215 int tout;
216 struct stat st;
217 char *ptr, *sav, *val;
218 int len;
219 char *bdev;
220 int fd;
221 char buf[32];
222 int n, m;
223 pid_t pid;
224
225 s -> lck = NULL;
226 if (prefix) {
227 binary = False;
228 lower = False;
229 upper = False;
230 sysv4 = False;
231 tout = 0;
232 if (method && (method = strdup (method))) {
233 for (ptr = method; *ptr; ) {
234 sav = ptr;
235 ptr = skipch (ptr, ',');
236 val = skipch (sav, '=');
237 len = strlen (sav);
238 for (n = 0; lckmth[n]; ++n)
239 if (! strncmp (lckmth[n], sav, len))
240 break;
241 switch (n) {
242 case 0: /* ascii */
243 binary = False;
244 break;
245 case 1: /* binary */
246 binary = True;
247 break;
248 case 2: /* lower */
249 lower = True;
250 upper = False;
251 break;
252 case 3: /* upper */
253 lower = False;
254 upper = True;
255 break;
256 case 4: /* sysv4 */
257 sysv4 = True;
258 break;
259 case 5: /* timeout */
260 tout = atoi (val);
261 break;
262 }
263 }
264 free (method);
265 }
266 if (sysv4) {
267 bdev = NULL;
268 if ((stat (dev, & st) != -1) && S_ISCHR (st.st_mode) && (bdev = malloc (96)))
269 sprintf (bdev, "%03d.%03d.%03d", major (st.st_dev), major (st.st_rdev), minor (st.st_rdev));
270 } else {
271 if (bdev = strrchr (dev, '/'))
272 ++bdev;
273 else
274 bdev = dev;
275 bdev = strdup (bdev);
276 }
277 len = strlen (prefix);
278 if (bdev && (s -> lck = malloc (len + strlen (bdev) + 4))) {
279 sprintf (s -> lck, "%s%s", prefix, bdev);
280 free (bdev);
281 if (upper || lower) {
282 ptr = s -> lck + len;
283 while (*ptr) {
284 if (lower)
285 *ptr = tolower (*ptr);
286 else if (upper)
287 *ptr = toupper (*ptr);
288 ++ptr;
289 }
290 }
291 do {
292 for (n = 0; n < 2; ++n) {
293 if ((fd = open (s -> lck, O_CREAT | O_EXCL | O_WRONLY, 0600)) != -1)
294 break;
295 if ((! n) && ((fd = open (s -> lck, O_RDONLY)) != -1)) {
296 pid = 0;
297 if (binary) {
298 if (read (fd, & pid, sizeof (pid)) != sizeof (pid))
299 pid = 0;
300 } else {
301 if ((m = read (fd, buf, sizeof (buf) - 1)) > 1) {
302 buf[m - 1] = '\0';
303 pid = (int) atoi (buf);
304 }
305 }
306 close (fd);
307 fd = -1;
308 if ((pid > 0) && (kill (pid, 0) < 0) && (errno == ESRCH))
309 unlink (s -> lck);
310 else
311 break;
312 }
313 }
314 if ((fd < 0) && (tout > 0))
315 sleep (1);
316 } while ((fd < 0) && (tout-- > 0));
317 if (fd != -1) {
318 pid = getpid ();
319 if (binary)
320 write (fd, & pid, sizeof (pid));
321 else {
322 sprintf (buf, "%10d\n", (int) pid);
323 write (fd, buf, strlen (buf));
324 }
325 # if HAVE_FCHMOD
326 fchmod (fd, 0644);
327 # else /* HAVE_FCHMOD */
328 chmod (s -> lck, 0644);
329 # endif /* HAVE_FCHMOD */
330 # if HAVE_FCHOWN
331 fchown (fd, geteuid (), getegid ());
332 # else /* HAVE_FCHOWN */
333 chown (s -> lck, geteuid (), getegid ());
334 # endif /* HAVE_FCHOWN */
335 close (fd);
336 } else {
337 free (s -> lck);
338 s -> lck = NULL;
339 return False;
340 }
341 } else {
342 if (bdev)
343 free (bdev);
344 return False;
345 }
346 }
347 return True;
348 }
349
350 static void
do_unlock(serial * s)351 do_unlock (serial *s)
352 {
353 if (s -> lck) {
354 unlink (s -> lck);
355 free (s -> lck);
356 s -> lck = NULL;
357 }
358 }
359 /*}}}*/
360 /*{{{ open/close/reopen */
361 void *
tty_open(char * dev,char * lckprefix,char * lckmethod)362 tty_open (char *dev, char *lckprefix, char *lckmethod)
363 {
364 serial *s;
365 int n;
366
367 if (s = (serial *) malloc (sizeof (serial))) {
368 # ifndef NDEBUG
369 s -> magic = MAGIC;
370 # endif /* NDEBUG */
371 if (do_lock (s, dev, lckprefix, lckmethod)) {
372 if ((s -> fd = open (dev, O_RDWR)) != -1) {
373 n = tcgetattr (s -> fd, & s -> sav);
374 if ((n < 0) || (! (s -> device = strdup (dev)))) {
375 close (s -> fd);
376 do_unlock (s);
377 free (s);
378 s = NULL;
379 } else {
380 s -> tty = s -> sav;
381 s -> line = NULL;
382 s -> sep = NULL;
383 s -> callback = NULL;
384 s -> data = NULL;
385 s -> suspend = False;
386 }
387 } else {
388 do_unlock (s);
389 free (s);
390 s = NULL;
391 }
392 } else {
393 free (s);
394 s = NULL;
395 }
396 }
397 return s;
398 }
399
400 void *
tty_close(void * sp)401 tty_close (void *sp)
402 {
403 serial *s = (serial *) sp;
404
405 MCHK (s);
406 if (s) {
407 if (s -> fd != -1) {
408 tcsetattr (s -> fd, TCSANOW, & s -> sav);
409 close (s -> fd);
410 }
411 do_unlock (s);
412 if (s -> device)
413 free (s -> device);
414 if (s -> sep)
415 free (s -> sep);
416 if (s -> line)
417 sfree (s -> line);
418 free (s);
419 }
420 return NULL;
421 }
422
423 Bool
tty_reopen(void * sp,int msec)424 tty_reopen (void *sp, int msec)
425 {
426 serial *s = (serial *) sp;
427
428 MCHK (s);
429 if (s -> fd != -1) {
430 close (s -> fd);
431 if (msec > 0)
432 msleep (msec);
433 s -> fd = -1;
434 }
435 if (s -> device && ((s -> fd = open (s -> device, O_RDWR)) != -1))
436 tcsetattr (s -> fd, TCSANOW, & s -> tty);
437 return s -> fd != -1 ? True : False;
438 }
439 /*}}}*/
440 /*{{{ hangup, get fd */
441 void
tty_hangup(void * sp,int msec)442 tty_hangup (void *sp, int msec)
443 {
444 serial *s = (serial *) sp;
445 struct termios tmp;
446
447 MCHK (s);
448 V (2, ("[Hangup] "));
449 if (s && (s -> fd != -1)) {
450 tmp = s -> tty;
451 cfsetispeed (& tmp, B0);
452 cfsetospeed (& tmp, B0);
453 if (tcsetattr (s -> fd, TCSANOW, & tmp) != -1) {
454 msleep (msec);
455 tcsetattr (s -> fd, TCSANOW, & s -> tty);
456 }
457 tty_reopen (s, msec);
458 }
459 V (2, ("\n"));
460 }
461
462 int
tty_fd(void * sp)463 tty_fd (void *sp)
464 {
465 serial *s = (serial *) sp;
466
467 MCHK (s);
468 return s ? s -> fd : -1;
469 }
470 /*}}}*/
471 /*{{{ configuration */
472 int
tty_setup(void * sp,Bool raw,Bool modem,int speed,int bpb,int sb,char par)473 tty_setup (void *sp, Bool raw, Bool modem, int speed, int bpb, int sb, char par)
474 {
475 serial *s = (serial *) sp;
476 int n;
477
478 MCHK (s);
479 if ((! s) || (s -> fd < 0))
480 return -1;
481 if ((bpb < 5) || (bpb > 8) ||
482 ((sb != 1) && (sb != 2)) ||
483 ((par != 'n') && (par != 'e') && (par != 'o')))
484 return -1;
485 for (n = 0; stab[n].speed > 0; ++n)
486 if (stab[n].speed == speed)
487 break;
488 if (stab[n].speed < 0)
489 return -1;
490 if (raw) {
491 s -> tty.c_iflag &= ~(IGNCR | ICRNL | INLCR | ISTRIP | IXON | IXOFF);
492 s -> tty.c_iflag |= IGNBRK;
493 s -> tty.c_oflag = 0;
494 s -> tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG);
495 # ifdef CRTSCTS
496 # ifdef sun
497 /* SunOS 4.x needs RTSCTS off if carrier detect is on */
498 /* but there is no carrier present (fkk) */
499 s -> tty.c_cflag &= ~CRTSCTS;
500 # else /* sun */
501 s -> tty.c_cflag |= CRTSCTS;
502 # endif /* sun */
503 # endif /* CRTSCTS */
504 s -> tty.c_cc[VMIN] = 0;
505 s -> tty.c_cc[VTIME] = 0;
506 } else {
507 s -> tty = s -> sav;
508 s -> tty.c_lflag |= ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG;
509 }
510 if (modem) {
511 # if 0
512 s -> tty.c_cflag &= ~CLOCAL;
513 # else
514 s -> tty.c_cflag |= CLOCAL;
515 # endif
516 s -> tty.c_cflag |= HUPCL;
517 } else {
518 s -> tty.c_cflag |= CLOCAL;
519 s -> tty.c_cflag &= ~HUPCL;
520 }
521 cfsetispeed (& s -> tty, stab[n].tok);
522 cfsetospeed (& s -> tty, stab[n].tok);
523 s -> tty.c_cflag &= ~(CSIZE);
524 s -> tty.c_cflag |= CREAD;
525 switch (sb) {
526 default:
527 case 1: s -> tty.c_cflag &= ~CSTOPB; break;
528 case 2: s -> tty.c_cflag |= CSTOPB; break;
529 }
530 switch (bpb) {
531 case 5: s -> tty.c_cflag |= CS5; break;
532 case 6: s -> tty.c_cflag |= CS6; break;
533 case 7: s -> tty.c_cflag |= CS7; break;
534 default:
535 case 8: s -> tty.c_cflag |= CS8; break;
536 }
537 switch (par) {
538 default:
539 case 'n':
540 s -> tty.c_cflag &= ~PARENB;
541 break;
542 case 'e':
543 s -> tty.c_cflag &= ~PARODD;
544 s -> tty.c_cflag |= PARENB;
545 break;
546 case 'o':
547 s -> tty.c_cflag |= PARENB | PARODD;
548 break;
549 }
550 return tcsetattr (s -> fd, TCSANOW, & s -> tty) < 0 ? -1 : 0;
551 }
552 /*}}}*/
553 /*{{{ callback */
554 void
tty_set_line_callback(void * sp,void (* func)(void *,string_t *,char_t,void *),char * sep,void * data)555 tty_set_line_callback (void *sp, void (*func) (void *, string_t *, char_t, void *), char *sep, void *data)
556 {
557 serial *s = (serial *) sp;
558
559 MCHK (s);
560 if (s) {
561 if (! (s -> callback = func)) {
562 if (s -> line)
563 s -> line = sfree (s -> line);
564 if (s -> sep) {
565 free (s -> sep);
566 s -> sep = NULL;
567 }
568 s -> data = NULL;
569 } else {
570 if (s -> sep)
571 free (s -> sep);
572 s -> sep = sep ? strdup (sep) : NULL;
573 s -> data = data;
574 }
575 s -> suspend = False;
576 }
577 }
578
579 void
tty_suspend_callback(void * sp,Bool susp)580 tty_suspend_callback (void *sp, Bool susp)
581 {
582 serial *s = (serial *) sp;
583
584 MCHK (s);
585 if (s)
586 if (s -> suspend = susp)
587 if (s -> line)
588 s -> line -> len = 0;
589 }
590 /*}}}*/
591 /*{{{ sending */
592 int
tty_send(void * sp,char * str,int len)593 tty_send (void *sp, char *str, int len)
594 {
595 serial *s = (serial *) sp;
596 int n, sent;
597
598 MCHK (s);
599 if ((! s) || (s -> fd < 0) || (! str))
600 return -1;
601 V (2, ("[Send] %s", mkprint (str, len)));
602 sent = 0;
603 while (len > 0)
604 if ((n = write (s -> fd, str, len)) > 0) {
605 str += n;
606 sent += n;
607 len -= n;
608 } else if (! n)
609 break;
610 else if (errno == EIO) {
611 if (! tty_reopen (s, 0))
612 break;
613 } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
614 msleep (200);
615 else if (errno != EINTR)
616 break;
617 V (2, ("\n"));
618 return sent;
619 }
620
621 int
tty_send_string(void * sp,char * str)622 tty_send_string (void *sp, char *str)
623 {
624 return str ? tty_send (sp, str, strlen (str)) : -1;
625 }
626 /*}}}*/
627 /*{{{ expecting */
628 static void
addline(serial * s,char ch)629 addline (serial *s, char ch)
630 {
631 if (s -> callback && s -> sep && (! s -> suspend) && ch) {
632 if (! s -> line)
633 s -> line = snew (NULL, 32);
634 else if (s -> line -> len + 1 >= s -> line -> size)
635 if (! sexpand (s -> line, s -> line -> size * 2))
636 return;
637 if (strchr (s -> sep, ch)) {
638 (*s -> callback) ((void *) s, s -> line, (char_t) ch, s -> data);
639 s -> line -> len = 0;
640 } else
641 s -> line -> str[s -> line -> len++] = (char_t) ch;
642 }
643 }
644
645 static int
do_expect(serial * s,int tout,expect * base)646 do_expect (serial *s, int tout, expect *base)
647 {
648 int ret;
649 int msec;
650 int n;
651 expect *run;
652 char ch;
653
654 if ((! s) || (s -> fd < 0))
655 return -1;
656 V (2, ("[Expect] "));
657 for (run = base; run; run = run -> next)
658 run -> pos = 0;
659 msec = (tout > 0) ? tout * 1000 : 0;
660 ret = 0;
661 while (! ret)
662 if ((n = data_ready (s -> fd, & msec)) > 0) {
663 while ((n = read (s -> fd, & ch, 1)) == 1) {
664 addline (s, ch);
665 V (3, ("%s", mkprint (& ch, 1)));
666 for (run = base; run; run = run -> next)
667 if (run -> str[run -> pos] == ch) {
668 run -> pos++;
669 if (run -> pos == run -> len) {
670 ret = run -> idx;
671 break;
672 }
673 } else
674 run -> pos = 0;
675 if (ret)
676 break;
677 }
678 if (n < 0)
679 if (errno == EIO)
680 tty_reopen (s, 0);
681 } else if (! n)
682 break;
683 if (verbose > 1)
684 if (run)
685 printf (" got %s", mkprint (run -> str, run -> len));
686 else
687 printf (" timeout");
688 V (2, ("\n"));
689 return ret;
690 }
691
692 int
tty_expect(void * sp,int tout,...)693 tty_expect (void *sp, int tout, ...)
694 {
695 va_list par;
696 int ret;
697 char *ptr;
698 expect *base, *prev, *tmp;
699 int idx;
700
701 va_start (par, tout);
702 MCHK ((serial *) sp);
703 ret = 0;
704 base = NULL;
705 prev = NULL;
706 idx = 1;
707 while (ptr = va_arg (par, char *))
708 if (tmp = (expect *) malloc (sizeof (expect))) {
709 tmp -> idx = idx++;
710 tmp -> str = ptr;
711 tmp -> pos = 0;
712 tmp -> len = va_arg (par, int);
713 tmp -> next = NULL;
714 if (prev)
715 prev -> next = tmp;
716 else
717 base = tmp;
718 prev = tmp;
719 } else
720 break;
721 if (! ptr)
722 ret = do_expect ((serial *) sp, tout, base);
723 else
724 ret = -1;
725 while (base) {
726 tmp = base;
727 base = base -> next;
728 free (tmp);
729 }
730 va_end (par);
731 return ret;
732 }
733
734 int
tty_expect_list(void * sp,int tout,char ** strs,int * lens)735 tty_expect_list (void *sp, int tout, char **strs, int *lens)
736 {
737 int n;
738 int ret;
739 expect *base, *prev, *tmp;
740
741 MCHK ((serial *) sp);
742 base = NULL;
743 prev = NULL;
744 for (n = 0; strs[n]; ++n)
745 if (tmp = (expect *) malloc (sizeof (expect))) {
746 tmp -> idx = n + 1;
747 tmp -> str = strs[n];
748 tmp -> pos = 0;
749 tmp -> len = lens[n];
750 tmp -> next = NULL;
751 if (prev)
752 prev -> next = tmp;
753 else
754 base = tmp;
755 prev = tmp;
756 } else
757 break;
758 if (strs[n])
759 ret = -1;
760 else
761 ret = do_expect ((serial *) sp, tout, base);
762 while (base) {
763 tmp = base;
764 base = base -> next;
765 free (tmp);
766 }
767 return ret;
768 }
769
770 int
tty_expect_string(void * sp,int tout,char * str)771 tty_expect_string (void *sp, int tout, char *str)
772 {
773 expect tmp;
774
775 MCHK ((serial *) sp);
776 if (! str)
777 return -1;
778 tmp.idx = 1;
779 tmp.str = str;
780 tmp.pos = 0;
781 tmp.len = strlen (str);
782 tmp.next = NULL;
783 return do_expect ((serial *) sp, tout, & tmp);
784 }
785 /*}}}*/
786 /*{{{ send/expect */
787 static int
tonum(char ch)788 tonum (char ch)
789 {
790 switch (ch) {
791 default:
792 case '0': return 0;
793 case '1': return 1;
794 case '2': return 2;
795 case '3': return 3;
796 case '4': return 4;
797 case '5': return 5;
798 case '6': return 6;
799 case '7': return 7;
800 case '8': return 8;
801 case '9': return 9;
802 }
803 }
804
805 static char *
expand(char * str,char ** opts,int ocnt)806 expand (char *str, char **opts, int ocnt)
807 {
808 char *ret;
809 int len, siz;
810 int idx, olen;
811
812 ret = NULL;
813 len = 0;
814 siz = 0;
815 while (*str) {
816 if (len >= siz) {
817 siz += (siz ? siz : 32);
818 if (! (ret = Realloc (ret, siz + 2)))
819 break;
820 }
821 if (*str == '\\') {
822 ++str;
823 if (*str) {
824 switch (*str) {
825 case 'a': ret[len++] = '\a'; break;
826 case 'b': ret[len++] = '\b'; break;
827 case 'f': ret[len++] = '\f'; break;
828 case 'l': ret[len++] = '\012'; break;
829 case 'n': ret[len++] = '\n'; break;
830 case 'r': ret[len++] = '\r'; break;
831 case 's': ret[len++] = ' '; break;
832 case 't': ret[len++] = '\t'; break;
833 default: ret[len++] = *str; break;
834 }
835 ++str;
836 }
837 } else if (*str == '^') {
838 ++str;
839 if (*str) {
840 if (*str == '?')
841 ret[len++] = '\x7f';
842 else
843 ret[len++] = *str & 0x1f;
844 ++str;
845 }
846 } else if (*str == '%') {
847 ++str;
848 idx = 0;
849 while (isdigit (*str)) {
850 idx *= 10;
851 idx += tonum (*str++);
852 }
853 if ((idx >= 0) && (idx < ocnt)) {
854 olen = strlen (opts[idx]);
855 if (len + olen >= siz) {
856 siz = len + olen + 64;
857 if (! (ret = Realloc (ret, siz + 2)))
858 break;
859 }
860 strcpy (ret + len, opts[idx]);
861 len += olen;
862 }
863 } else if ((*str == '\'') || (*str == '"'))
864 ++str;
865 else
866 ret[len++] = *str++;
867 }
868 if (ret)
869 ret[len] = '\0';
870 return ret;
871 }
872
873 static int
handle_command(void * sp,char * str)874 handle_command (void *sp, char *str)
875 {
876 serial *s = (serial *) sp;
877 char *p1;
878 int mult;
879 int ret;
880
881 ret = 0;
882 V (2, ("[Cmd"));
883 for (p1 = str; *p1; ) {
884 if (isdigit (*p1)) {
885 mult = 0;
886 while (isdigit (*p1)) {
887 mult *= 10;
888 mult += tonum (*p1++);
889 }
890 } else
891 mult = 1;
892 if (*p1)
893 switch (*p1++) {
894 case 'd':
895 V (2, (" Dzz %d", mult));
896 sleep (mult);
897 break;
898 case 'D':
899 V (2, (" Mdzz %d", mult));
900 msleep (mult);
901 break;
902 case 'b':
903 if (s && (s -> fd != -1)) {
904 V (2, (" Brk %d", mult));
905 tcsendbreak (s -> fd, mult);
906 }
907 break;
908 case 'h':
909 if (s && (s -> fd != -1)) {
910 V (2, (" Hup"));
911 tty_hangup (sp, mult * 500);
912 }
913 break;
914 case 'o':
915 if (s && (s -> fd != -1)) {
916 V (2, (" Drain"));
917 tcdrain (s -> fd);
918 }
919 break;
920 case '<':
921 if (s && (s -> fd != -1)) {
922 V (2, (" Iflush"));
923 tcflush (s -> fd, TCIFLUSH);
924 }
925 break;
926 case '>':
927 if (s && (s -> fd != -1)) {
928 V (2, (" Oflush"));
929 tcflush (s -> fd, TCOFLUSH);
930 }
931 break;
932 case 'f':
933 V (2, (" fail"));
934 ret = -1;
935 break;
936 case 's':
937 V (2, (" success"));
938 ret = 1;
939 break;
940 }
941 }
942 V (2, ("]\n"));
943 return ret;
944 }
945
946 static int
expect_expr(void * sp,int deftout,char * line)947 expect_expr (void *sp, int deftout, char *line)
948 {
949 int ret;
950 char **ex;
951 int cnt, siz;
952 int n, m, tout, slen;
953 char *ptr;
954 char *p1, *p2;
955 char **list;
956 int *len;
957
958 MCHK ((serial *) sp);
959 ex = NULL;
960 cnt = 0;
961 siz = 0;
962 for (ptr = line; *ptr; ) {
963 if (cnt >= siz) {
964 siz += 4;
965 if (! (ex = (char **) Realloc (ex, (siz + 1) * sizeof (char *))))
966 break;
967 }
968 ex[cnt++] = ptr;
969 while (*ptr && (*ptr != '-'))
970 ++ptr;
971 if (*ptr)
972 *ptr++ = '\0';
973 }
974 if (! ex)
975 return -1;
976 ret = 0;
977 for (n = 0; n < cnt; ++n) {
978 ptr = ex[n];
979 if (isdigit (*ptr)) {
980 tout = 0;
981 while (isdigit (*ptr)) {
982 tout *= 10;
983 tout += tonum (*ptr++);
984 }
985 } else
986 tout = deftout;
987 p1 = ptr;
988 for (siz = 1, p2 = p1; p2; p2 = strchr (p2, '|'))
989 ++siz, ++p2;
990 if ((list = (char **) malloc ((siz + 1) * sizeof (char *))) &&
991 (len = (int *) malloc ((siz + 1) * sizeof (int)))) {
992 for (n = 0, p1 = ptr; p1; ++n) {
993 p2 = p1;
994 if (p1 = strchr (p1, '|'))
995 *p1++ = '\0';
996 list[n] = p2;
997 len[n] = strlen (p2);
998 }
999 list[n] = NULL;
1000 len[n] = 0;
1001 if (tty_expect_list (sp, tout, list, len) != 1)
1002 ret = -1;
1003 free (list);
1004 free (len);
1005 } else {
1006 ret = -1;
1007 break;
1008 }
1009 if ((ret < 0) && (n + 1 < cnt)) {
1010 ++n;
1011 ptr = ex[n];
1012 ret = 0;
1013 if (*ptr == '!') {
1014 if (m = handle_command (sp, ptr + 1)) {
1015 if (m < 0)
1016 ret = -1;
1017 break;
1018 }
1019 } else {
1020 slen = strlen (ptr);
1021 if (tty_send (sp, ptr, slen) != slen) {
1022 ret = -1;
1023 break;
1024 }
1025 }
1026 } else
1027 n = cnt;
1028 }
1029 if (ex)
1030 free (ex);
1031 return ret;
1032 }
1033
1034 int
tty_send_expect(void * sp,int deftout,char * str,char ** opts)1035 tty_send_expect (void *sp, int deftout, char *str, char **opts)
1036 {
1037 serial *s = (serial *) sp;
1038 int ret;
1039 int ocnt;
1040 char *sav, *ptr, *line;
1041 int n;
1042 char quote;
1043 Bool esc;
1044
1045 MCHK (s);
1046 ret = -1;
1047 if (opts)
1048 for (ocnt = 0; opts[ocnt]; ++ocnt)
1049 ;
1050 else
1051 ocnt = 0;
1052 if (str = strdup (str)) {
1053 ret = 0;
1054 for (ptr = str; *ptr && (! ret); ) {
1055 sav = ptr;
1056 esc = False;
1057 quote = '\0';
1058 while (*ptr) {
1059 if (esc)
1060 esc = False;
1061 else if (*ptr == '\\')
1062 esc = True;
1063 else if (quote) {
1064 if (*ptr == quote)
1065 quote = '\0';
1066 } else if ((*ptr == '\'') || (*ptr == '"'))
1067 quote = *ptr;
1068 else if (isspace (*ptr))
1069 break;
1070 ++ptr;
1071 }
1072 if (*ptr) {
1073 *ptr++ = '\0';
1074 while (isspace (*ptr))
1075 ++ptr;
1076 }
1077 if (line = expand (sav, opts, ocnt)) {
1078 if (line[0] == '<') {
1079 if (expect_expr (sp, deftout, line + 1) < 0)
1080 ret = -1;
1081 } else if (line[0] == '!') {
1082 if ((n = handle_command (sp, line + 1)) < 0)
1083 ret = -1;
1084 else if (n > 0)
1085 while (*ptr)
1086 ++ptr;
1087 } else {
1088 n = strlen (line);
1089 if (tty_send (sp, line, n) != n)
1090 ret = -1;
1091 }
1092 free (line);
1093 } else
1094 ret = -1;
1095 }
1096 free (str);
1097 }
1098 return ret;
1099 }
1100 /*}}}*/
1101 /*{{{ draining */
1102 void
tty_mdrain(void * sp,int msecs)1103 tty_mdrain (void *sp, int msecs)
1104 {
1105 serial *s = (serial *) sp;
1106 int n, m;
1107 char ch;
1108
1109 MCHK (s);
1110 if (s && (s -> fd != -1)) {
1111 V (2, ("[Drain] "));
1112 if (msecs < 0)
1113 msecs = 0;
1114 do {
1115 if ((n = data_ready (s -> fd, & msecs)) > 0) {
1116 while ((m = read (s -> fd, & ch, 1)) == 1) {
1117 addline (s, ch);
1118 V (2, ("%s", mkprint (& ch, 1)));
1119 }
1120 if (m < 0)
1121 if (errno == EIO)
1122 tty_reopen (s, 0);
1123 }
1124 } while (n != 0);
1125 V (2, ("\n"));
1126 }
1127 }
1128
1129 void
tty_drain(void * sp,int secs)1130 tty_drain (void *sp, int secs)
1131 {
1132 tty_mdrain (sp, secs * 1000);
1133 }
1134 /*}}}*/
1135