xref: /freebsd/libexec/getty/chat.c (revision d748864d2c912637ecc3d55874df9af6ff5c2c8f)
1fe552114SDavid Nugent /*-
2fe552114SDavid Nugent  * Copyright (c) 1997
3fe552114SDavid Nugent  *	David L Nugent <davidn@blaze.net.au>.
4fe552114SDavid Nugent  *	All rights reserved.
5fe552114SDavid Nugent  *
6fe552114SDavid Nugent  *
7fe552114SDavid Nugent  * Redistribution and use in source and binary forms, with or without
8fe552114SDavid Nugent  * modification, is permitted provided that the following conditions
9fe552114SDavid Nugent  * are met:
10fe552114SDavid Nugent  * 1. Redistributions of source code must retain the above copyright
11fe552114SDavid Nugent  *    notice immediately at the beginning of the file, without modification,
12fe552114SDavid Nugent  *    this list of conditions, and the following disclaimer.
13fe552114SDavid Nugent  * 2. Redistributions in binary form must reproduce the above copyright
14fe552114SDavid Nugent  *    notice, this list of conditions and the following disclaimer in the
15fe552114SDavid Nugent  *    documentation and/or other materials provided with the distribution.
16fe552114SDavid Nugent  * 3. This work was done expressly for inclusion into FreeBSD.  Other use
17fe552114SDavid Nugent  *    is permitted provided this notation is included.
18fe552114SDavid Nugent  * 4. Absolutely no warranty of function or purpose is made by the authors.
19fe552114SDavid Nugent  * 5. Modifications may be freely made to this file providing the above
20fe552114SDavid Nugent  *    conditions are met.
21fe552114SDavid Nugent  *
22fe552114SDavid Nugent  * Modem chat module - send/expect style functions for getty
23fe552114SDavid Nugent  * For semi-intelligent modem handling.
24fe552114SDavid Nugent  */
25fe552114SDavid Nugent 
26d748864dSPhilippe Charnier #ifndef lint
27d748864dSPhilippe Charnier static const char rcsid[] =
28d748864dSPhilippe Charnier 	"$Id$";
29d748864dSPhilippe Charnier #endif /* not lint */
30d748864dSPhilippe Charnier 
31fe552114SDavid Nugent #include <sys/param.h>
32fe552114SDavid Nugent #include <sys/stat.h>
33fe552114SDavid Nugent #include <sys/ioctl.h>
34fe552114SDavid Nugent #include <sys/resource.h>
35fe552114SDavid Nugent #include <sys/ttydefaults.h>
36fe552114SDavid Nugent #include <sys/utsname.h>
37fe552114SDavid Nugent #include <ctype.h>
38d748864dSPhilippe Charnier #include <errno.h>
39fe552114SDavid Nugent #include <fcntl.h>
40fe552114SDavid Nugent #include <libutil.h>
41fe552114SDavid Nugent #include <locale.h>
42fe552114SDavid Nugent #include <setjmp.h>
43fe552114SDavid Nugent #include <signal.h>
44fe552114SDavid Nugent #include <stdlib.h>
45fe552114SDavid Nugent #include <string.h>
46fe552114SDavid Nugent #include <syslog.h>
47fe552114SDavid Nugent #include <time.h>
48d748864dSPhilippe Charnier #include <termios.h>
49fe552114SDavid Nugent #include <unistd.h>
50fe552114SDavid Nugent #include <sys/socket.h>
51fe552114SDavid Nugent 
52fe552114SDavid Nugent #include "extern.h"
53fe552114SDavid Nugent 
54fe552114SDavid Nugent #define	PAUSE_CH		(unsigned char)'\xff'   /* pause kludge */
55fe552114SDavid Nugent 
56fe552114SDavid Nugent #define	CHATDEBUG_RECEIVE	0x01
57fe552114SDavid Nugent #define	CHATDEBUG_SEND		0x02
58fe552114SDavid Nugent #define	CHATDEBUG_EXPECT	0x04
59fe552114SDavid Nugent #define	CHATDEBUG_MISC		0x08
60fe552114SDavid Nugent 
61fe552114SDavid Nugent #define	CHATDEBUG_DEFAULT	0
62fe552114SDavid Nugent #define CHAT_DEFAULT_TIMEOUT	10
63fe552114SDavid Nugent 
64fe552114SDavid Nugent 
65fe552114SDavid Nugent static int chat_debug = CHATDEBUG_DEFAULT;
66fe552114SDavid Nugent static int chat_alarm = CHAT_DEFAULT_TIMEOUT; /* Default */
67fe552114SDavid Nugent 
68fe552114SDavid Nugent static volatile int alarmed = 0;
69fe552114SDavid Nugent 
70fe552114SDavid Nugent 
71fe552114SDavid Nugent static void   chat_alrm __P((int));
72fe552114SDavid Nugent static int    chat_unalarm __P((void));
73fe552114SDavid Nugent static int    getdigit __P((unsigned char **, int, int));
74fe552114SDavid Nugent static char   **read_chat __P((char **));
75fe552114SDavid Nugent static char   *cleanchr __P((char **, unsigned char));
76fe552114SDavid Nugent static char   *cleanstr __P((const unsigned char *, int));
77fe552114SDavid Nugent static const char *result __P((int));
78fe552114SDavid Nugent static int    chat_expect __P((const char *));
79fe552114SDavid Nugent static int    chat_send __P((char const *));
80fe552114SDavid Nugent 
81fe552114SDavid Nugent 
82fe552114SDavid Nugent /*
83fe552114SDavid Nugent  * alarm signal handler
84fe552114SDavid Nugent  * handle timeouts in read/write
85fe552114SDavid Nugent  * change stdin to non-blocking mode to prevent
86fe552114SDavid Nugent  * possible hang in read().
87fe552114SDavid Nugent  */
88fe552114SDavid Nugent 
89fe552114SDavid Nugent static void
90fe552114SDavid Nugent chat_alrm(signo)
91fe552114SDavid Nugent 	int signo;
92fe552114SDavid Nugent {
93fe552114SDavid Nugent 	int on = 1;
94fe552114SDavid Nugent 
95fe552114SDavid Nugent 	alarm(1);
96fe552114SDavid Nugent 	alarmed = 1;
97fe552114SDavid Nugent 	signal(SIGALRM, chat_alrm);
98fe552114SDavid Nugent 	ioctl(STDIN_FILENO, FIONBIO, &on);
99fe552114SDavid Nugent }
100fe552114SDavid Nugent 
101fe552114SDavid Nugent 
102fe552114SDavid Nugent /*
103fe552114SDavid Nugent  * Turn back on blocking mode reset by chat_alrm()
104fe552114SDavid Nugent  */
105fe552114SDavid Nugent 
106fe552114SDavid Nugent static int
107fe552114SDavid Nugent chat_unalarm()
108fe552114SDavid Nugent {
109fe552114SDavid Nugent 	int off = 0;
110fe552114SDavid Nugent 	return ioctl(STDIN_FILENO, FIONBIO, &off);
111fe552114SDavid Nugent }
112fe552114SDavid Nugent 
113fe552114SDavid Nugent 
114fe552114SDavid Nugent /*
115fe552114SDavid Nugent  * convert a string of a given base (octal/hex) to binary
116fe552114SDavid Nugent  */
117fe552114SDavid Nugent 
118fe552114SDavid Nugent static int
119fe552114SDavid Nugent getdigit(ptr, base, max)
120fe552114SDavid Nugent 	unsigned char **ptr;
121fe552114SDavid Nugent 	int base, max;
122fe552114SDavid Nugent {
123fe552114SDavid Nugent 	int i, val = 0;
124fe552114SDavid Nugent 	char * q;
125fe552114SDavid Nugent 
126fe552114SDavid Nugent 	static const char xdigits[] = "0123456789abcdef";
127fe552114SDavid Nugent 
128fe552114SDavid Nugent 	for (i = 0, q = *ptr; i++ < max; ++q) {
129fe552114SDavid Nugent 		int sval;
130fe552114SDavid Nugent 		const char * s = strchr(xdigits, tolower(*q));
131fe552114SDavid Nugent 
132fe552114SDavid Nugent 		if (s == NULL || (sval = s - xdigits) >= base)
133fe552114SDavid Nugent 			break;
134fe552114SDavid Nugent 		val = (val * base) + sval;
135fe552114SDavid Nugent 	}
136fe552114SDavid Nugent 	*ptr = q;
137fe552114SDavid Nugent 	return val;
138fe552114SDavid Nugent }
139fe552114SDavid Nugent 
140fe552114SDavid Nugent 
141fe552114SDavid Nugent /*
142fe552114SDavid Nugent  * read_chat()
143fe552114SDavid Nugent  * Convert a whitespace delimtied string into an array
144fe552114SDavid Nugent  * of strings, being expect/send pairs
145fe552114SDavid Nugent  */
146fe552114SDavid Nugent 
147fe552114SDavid Nugent static char **
148fe552114SDavid Nugent read_chat(chatstr)
149fe552114SDavid Nugent 	char **chatstr;
150fe552114SDavid Nugent {
151fe552114SDavid Nugent 	char *str = *chatstr;
152fe552114SDavid Nugent 	char **res = NULL;
153fe552114SDavid Nugent 
154fe552114SDavid Nugent 	if (str != NULL) {
155fe552114SDavid Nugent 		char *tmp = NULL;
156fe552114SDavid Nugent 		int l;
157fe552114SDavid Nugent 
158fe552114SDavid Nugent 		if ((l=strlen(str)) > 0 && (tmp=malloc(l + 1)) != NULL &&
159fe552114SDavid Nugent 		    (res=malloc((l / 2 + 1) * sizeof(char *))) != NULL) {
160fe552114SDavid Nugent 			static char ws[] = " \t";
161fe552114SDavid Nugent 			char * p;
162fe552114SDavid Nugent 
163fe552114SDavid Nugent 			for (l = 0, p = strtok(strcpy(tmp, str), ws);
164fe552114SDavid Nugent 			     p != NULL;
165fe552114SDavid Nugent 			     p = strtok(NULL, ws))
166fe552114SDavid Nugent 			{
167fe552114SDavid Nugent 				unsigned char *q, *r;
168fe552114SDavid Nugent 
169fe552114SDavid Nugent 				/* Read escapes */
170fe552114SDavid Nugent 				for (q = r = (unsigned char *)p; *r; ++q)
171fe552114SDavid Nugent 				{
172fe552114SDavid Nugent 					if (*q == '\\')
173fe552114SDavid Nugent 					{
174fe552114SDavid Nugent 						/* handle special escapes */
175fe552114SDavid Nugent 						switch (*++q)
176fe552114SDavid Nugent 						{
177fe552114SDavid Nugent 						case 'a': /* bell */
178fe552114SDavid Nugent 							*r++ = '\a';
179fe552114SDavid Nugent 							break;
180fe552114SDavid Nugent 						case 'r': /* cr */
181fe552114SDavid Nugent 							*r++ = '\r';
182fe552114SDavid Nugent 							break;
183fe552114SDavid Nugent 						case 'n': /* nl */
184fe552114SDavid Nugent 							*r++ = '\n';
185fe552114SDavid Nugent 							break;
186fe552114SDavid Nugent 						case 'f': /* ff */
187fe552114SDavid Nugent 							*r++ = '\f';
188fe552114SDavid Nugent 							break;
189fe552114SDavid Nugent 						case 'b': /* bs */
190fe552114SDavid Nugent 							*r++ = '\b';
191fe552114SDavid Nugent 							break;
192fe552114SDavid Nugent 						case 'e': /* esc */
193fe552114SDavid Nugent 							*r++ = 27;
194fe552114SDavid Nugent 							break;
195fe552114SDavid Nugent 						case 't': /* tab */
196fe552114SDavid Nugent 							*r++ = '\t';
197fe552114SDavid Nugent 							break;
198fe552114SDavid Nugent 						case 'p': /* pause */
199fe552114SDavid Nugent 							*r++ = PAUSE_CH;
200fe552114SDavid Nugent 							break;
201fe552114SDavid Nugent 						case 's':
202fe552114SDavid Nugent 						case 'S': /* space */
203fe552114SDavid Nugent 							*r++ = ' ';
204fe552114SDavid Nugent 							break;
205fe552114SDavid Nugent 						case 'x': /* hexdigit */
206fe552114SDavid Nugent 							++q;
207fe552114SDavid Nugent 							*r++ = getdigit(&q, 16, 2);
208fe552114SDavid Nugent 							--q;
209fe552114SDavid Nugent 							break;
210fe552114SDavid Nugent 						case '0': /* octal */
211fe552114SDavid Nugent 							++q;
212fe552114SDavid Nugent 							*r++ = getdigit(&q, 8, 3);
213fe552114SDavid Nugent 							--q;
214fe552114SDavid Nugent 							break;
215fe552114SDavid Nugent 						default: /* literal */
216fe552114SDavid Nugent 							*r++ = *q;
217fe552114SDavid Nugent 							break;
218fe552114SDavid Nugent 						case 0: /* not past eos */
219fe552114SDavid Nugent 							--q;
220fe552114SDavid Nugent 							break;
221fe552114SDavid Nugent 						}
222fe552114SDavid Nugent 					} else {
223fe552114SDavid Nugent 						/* copy standard character */
224b92f6bd2SDavid Nugent 						*r++ = *q;
225fe552114SDavid Nugent 					}
226fe552114SDavid Nugent 				}
227fe552114SDavid Nugent 
228fe552114SDavid Nugent 				/* Remove surrounding quotes, if any
229fe552114SDavid Nugent 				 */
230fe552114SDavid Nugent 				if (*p == '"' || *p == '\'') {
231fe552114SDavid Nugent 					q = strrchr(p+1, *p);
232fe552114SDavid Nugent 					if (q != NULL && *q == *p && q[1] == '\0') {
233fe552114SDavid Nugent 						*q = '\0';
234fe552114SDavid Nugent 						strcpy(p, p+1);
235fe552114SDavid Nugent 					}
236fe552114SDavid Nugent 				}
237fe552114SDavid Nugent 
238fe552114SDavid Nugent 				res[l++] = p;
239fe552114SDavid Nugent 			}
240fe552114SDavid Nugent 			res[l] = NULL;
241fe552114SDavid Nugent 			*chatstr = tmp;
242fe552114SDavid Nugent 			return res;
243fe552114SDavid Nugent 		}
244fe552114SDavid Nugent 		free(tmp);
245fe552114SDavid Nugent 	}
246fe552114SDavid Nugent 	return res;
247fe552114SDavid Nugent }
248fe552114SDavid Nugent 
249fe552114SDavid Nugent 
250fe552114SDavid Nugent /*
251fe552114SDavid Nugent  * clean a character for display (ctrl/meta character)
252fe552114SDavid Nugent  */
253fe552114SDavid Nugent 
254fe552114SDavid Nugent static char *
255fe552114SDavid Nugent cleanchr(buf, ch)
256fe552114SDavid Nugent 	char **buf;
257fe552114SDavid Nugent 	unsigned char ch;
258fe552114SDavid Nugent {
259fe552114SDavid Nugent 	int l;
260fe552114SDavid Nugent 	static char tmpbuf[5];
261fe552114SDavid Nugent 	char * tmp = buf ? *buf : tmpbuf;
262fe552114SDavid Nugent 
263fe552114SDavid Nugent 	if (ch & 0x80) {
264fe552114SDavid Nugent 		strcpy(tmp, "M-");
265fe552114SDavid Nugent 		l = 2;
266fe552114SDavid Nugent 		ch &= 0x7f;
267fe552114SDavid Nugent 	} else
268fe552114SDavid Nugent 	l = 0;
269fe552114SDavid Nugent 
270fe552114SDavid Nugent 	if (ch < 32) {
271fe552114SDavid Nugent 		tmp[l++] = '^';
272fe552114SDavid Nugent 		tmp[l++] = ch + '@';
273fe552114SDavid Nugent 	} else if (ch == 127) {
274fe552114SDavid Nugent 		tmp[l++] = '^';
275fe552114SDavid Nugent 		tmp[l++] = '?';
276fe552114SDavid Nugent 	} else
277fe552114SDavid Nugent 		tmp[l++] = ch;
278fe552114SDavid Nugent 	tmp[l] = '\0';
279fe552114SDavid Nugent 
280fe552114SDavid Nugent 	if (buf)
281fe552114SDavid Nugent 		*buf = tmp + l;
282fe552114SDavid Nugent 	return tmp;
283fe552114SDavid Nugent }
284fe552114SDavid Nugent 
285fe552114SDavid Nugent 
286fe552114SDavid Nugent /*
287fe552114SDavid Nugent  * clean a string for display (ctrl/meta characters)
288fe552114SDavid Nugent  */
289fe552114SDavid Nugent 
290fe552114SDavid Nugent static char *
291fe552114SDavid Nugent cleanstr(s, l)
292fe552114SDavid Nugent 	const unsigned char *s;
293fe552114SDavid Nugent 	int l;
294fe552114SDavid Nugent {
295fe552114SDavid Nugent 	static unsigned char * tmp = NULL;
296fe552114SDavid Nugent 	static int tmplen = 0;
297fe552114SDavid Nugent 
298fe552114SDavid Nugent 	if (tmplen < l * 4 + 1)
299fe552114SDavid Nugent 		tmp = realloc(tmp, tmplen = l * 4 + 1);
300fe552114SDavid Nugent 
301fe552114SDavid Nugent 	if (tmp == NULL) {
302fe552114SDavid Nugent 		tmplen = 0;
303fe552114SDavid Nugent 		return (char *)"(mem alloc error)";
304fe552114SDavid Nugent 	} else {
305fe552114SDavid Nugent 		int i = 0;
306fe552114SDavid Nugent 		char * p = tmp;
307fe552114SDavid Nugent 
308fe552114SDavid Nugent 		while (i < l)
309fe552114SDavid Nugent 			cleanchr(&p, s[i++]);
310fe552114SDavid Nugent 		*p = '\0';
311fe552114SDavid Nugent 	}
312fe552114SDavid Nugent 
313fe552114SDavid Nugent 	return tmp;
314fe552114SDavid Nugent }
315fe552114SDavid Nugent 
316fe552114SDavid Nugent 
317fe552114SDavid Nugent /*
318fe552114SDavid Nugent  * return result as an pseudo-english word
319fe552114SDavid Nugent  */
320fe552114SDavid Nugent 
321fe552114SDavid Nugent static const char *
322fe552114SDavid Nugent result(r)
323fe552114SDavid Nugent 	int r;
324fe552114SDavid Nugent {
325fe552114SDavid Nugent 	static const char * results[] = {
326fe552114SDavid Nugent 		"OK", "MEMERROR", "IOERROR", "TIMEOUT"
327fe552114SDavid Nugent 	};
328fe552114SDavid Nugent 	return results[r & 3];
329fe552114SDavid Nugent }
330fe552114SDavid Nugent 
331fe552114SDavid Nugent 
332fe552114SDavid Nugent /*
333fe552114SDavid Nugent  * chat_expect()
334fe552114SDavid Nugent  * scan input for an expected string
335fe552114SDavid Nugent  */
336fe552114SDavid Nugent 
337fe552114SDavid Nugent static int
338fe552114SDavid Nugent chat_expect(str)
339fe552114SDavid Nugent 	const char *str;
340fe552114SDavid Nugent {
341fe552114SDavid Nugent 	int len, r = 0;
342fe552114SDavid Nugent 
343fe552114SDavid Nugent 	if (chat_debug & CHATDEBUG_EXPECT)
344fe552114SDavid Nugent 		syslog(LOG_DEBUG, "chat_expect '%s'", cleanstr(str, strlen(str)));
345fe552114SDavid Nugent 
346fe552114SDavid Nugent 	if ((len = strlen(str)) > 0) {
347fe552114SDavid Nugent 		int i = 0;
348fe552114SDavid Nugent 		char * got;
349fe552114SDavid Nugent 
350fe552114SDavid Nugent 		if ((got = malloc(len + 1)) == NULL)
351fe552114SDavid Nugent 			r = 1;
352fe552114SDavid Nugent 		else {
353fe552114SDavid Nugent 
354fe552114SDavid Nugent 			memset(got, 0, len+1);
355fe552114SDavid Nugent 			alarm(chat_alarm);
356fe552114SDavid Nugent 			alarmed = 0;
357fe552114SDavid Nugent 
358fe552114SDavid Nugent 			while (r == 0 && i < len) {
359fe552114SDavid Nugent 				if (alarmed)
360fe552114SDavid Nugent 					r = 3;
361fe552114SDavid Nugent 				else {
362fe552114SDavid Nugent 					unsigned char ch;
363fe552114SDavid Nugent 
364fe552114SDavid Nugent 					if (read(STDIN_FILENO, &ch, 1) == 1) {
365fe552114SDavid Nugent 
366fe552114SDavid Nugent 						if (chat_debug & CHATDEBUG_RECEIVE)
367fe552114SDavid Nugent 							syslog(LOG_DEBUG, "chat_recv '%s' m=%d",
368fe552114SDavid Nugent 								cleanchr(NULL, ch), i);
369fe552114SDavid Nugent 
370fe552114SDavid Nugent 						if (ch == str[i])
371fe552114SDavid Nugent 							got[i++] = ch;
372fe552114SDavid Nugent 						else if (i > 0) {
373fe552114SDavid Nugent 							int j = 1;
374fe552114SDavid Nugent 
375fe552114SDavid Nugent 							/* See if we can resync on a
376fe552114SDavid Nugent 							 * partial match in our buffer
377fe552114SDavid Nugent 							 */
378fe552114SDavid Nugent 							while (j < i && memcmp(got + j, str, i - j) != NULL)
379fe552114SDavid Nugent 								j++;
380fe552114SDavid Nugent 							if (j < i)
381fe552114SDavid Nugent 								memcpy(got, got + j, i - j);
382fe552114SDavid Nugent 							i -= j;
383fe552114SDavid Nugent 						}
384fe552114SDavid Nugent 					} else
385fe552114SDavid Nugent 						r = alarmed ? 3 : 2;
386fe552114SDavid Nugent 				}
387fe552114SDavid Nugent 			}
388fe552114SDavid Nugent 			alarm(0);
389fe552114SDavid Nugent         		chat_unalarm();
390fe552114SDavid Nugent         		alarmed = 0;
391fe552114SDavid Nugent         		free(got);
392fe552114SDavid Nugent 		}
393fe552114SDavid Nugent 	}
394fe552114SDavid Nugent 
395fe552114SDavid Nugent 	if (chat_debug & CHATDEBUG_EXPECT)
396fe552114SDavid Nugent 		syslog(LOG_DEBUG, "chat_expect %s", result(r));
397fe552114SDavid Nugent 
398fe552114SDavid Nugent 	return r;
399fe552114SDavid Nugent }
400fe552114SDavid Nugent 
401fe552114SDavid Nugent 
402fe552114SDavid Nugent /*
403fe552114SDavid Nugent  * chat_send()
404fe552114SDavid Nugent  * send a chat string
405fe552114SDavid Nugent  */
406fe552114SDavid Nugent 
407fe552114SDavid Nugent static int
408fe552114SDavid Nugent chat_send(str)
409fe552114SDavid Nugent 	char const *str;
410fe552114SDavid Nugent {
411fe552114SDavid Nugent 	int r = 0;
412fe552114SDavid Nugent 
413fe552114SDavid Nugent 	if (chat_debug && CHATDEBUG_SEND)
414fe552114SDavid Nugent 		syslog(LOG_DEBUG, "chat_send '%s'", cleanstr(str, strlen(str)));
415fe552114SDavid Nugent 
416fe552114SDavid Nugent 	if (*str) {
417fe552114SDavid Nugent                 alarm(chat_alarm);
418fe552114SDavid Nugent                 alarmed = 0;
419fe552114SDavid Nugent                 while (r == 0 && *str)
420fe552114SDavid Nugent                 {
421fe552114SDavid Nugent                         unsigned char ch = (unsigned char)*str++;
422fe552114SDavid Nugent 
423fe552114SDavid Nugent                         if (alarmed)
424fe552114SDavid Nugent         			r = 3;
425fe552114SDavid Nugent                         else if (ch == PAUSE_CH)
426fe552114SDavid Nugent 				usleep(500000); /* 1/2 second */
427fe552114SDavid Nugent 			else  {
428fe552114SDavid Nugent 				usleep(10000);	/* be kind to modem */
429fe552114SDavid Nugent                                 if (write(STDOUT_FILENO, &ch, 1) != 1)
430fe552114SDavid Nugent         		  		r = alarmed ? 3 : 2;
431fe552114SDavid Nugent                         }
432fe552114SDavid Nugent                 }
433fe552114SDavid Nugent                 alarm(0);
434fe552114SDavid Nugent                 chat_unalarm();
435fe552114SDavid Nugent                 alarmed = 0;
436fe552114SDavid Nugent 	}
437fe552114SDavid Nugent 
438fe552114SDavid Nugent         if (chat_debug & CHATDEBUG_SEND)
439fe552114SDavid Nugent           syslog(LOG_DEBUG, "chat_send %s", result(r));
440fe552114SDavid Nugent 
441fe552114SDavid Nugent         return r;
442fe552114SDavid Nugent }
443fe552114SDavid Nugent 
444fe552114SDavid Nugent 
445fe552114SDavid Nugent /*
446fe552114SDavid Nugent  * getty_chat()
447fe552114SDavid Nugent  *
448fe552114SDavid Nugent  * Termination codes:
449fe552114SDavid Nugent  * -1 - no script supplied
450fe552114SDavid Nugent  *  0 - script terminated correctly
451fe552114SDavid Nugent  *  1 - invalid argument, expect string too large, etc.
452fe552114SDavid Nugent  *  2 - error on an I/O operation or fatal error condition
453fe552114SDavid Nugent  *  3 - timeout waiting for a simple string
454fe552114SDavid Nugent  *
455fe552114SDavid Nugent  * Parameters:
456fe552114SDavid Nugent  *  char *scrstr     - unparsed chat script
457fe552114SDavid Nugent  *  timeout          - seconds timeout
458fe552114SDavid Nugent  *  debug            - debug value (bitmask)
459fe552114SDavid Nugent  */
460fe552114SDavid Nugent 
461fe552114SDavid Nugent int
462fe552114SDavid Nugent getty_chat(scrstr, timeout, debug)
463fe552114SDavid Nugent 	char *scrstr;
464fe552114SDavid Nugent 	int timeout, debug;
465fe552114SDavid Nugent {
466fe552114SDavid Nugent         int r = -1;
467fe552114SDavid Nugent 
468fe552114SDavid Nugent         chat_alarm = timeout ? timeout : CHAT_DEFAULT_TIMEOUT;
469fe552114SDavid Nugent         chat_debug = debug;
470fe552114SDavid Nugent 
471fe552114SDavid Nugent         if (scrstr != NULL) {
472fe552114SDavid Nugent                 char **script;
473fe552114SDavid Nugent 
474fe552114SDavid Nugent                 if (chat_debug & CHATDEBUG_MISC)
475fe552114SDavid Nugent 			syslog(LOG_DEBUG, "getty_chat script='%s'", scrstr);
476fe552114SDavid Nugent 
477fe552114SDavid Nugent                 if ((script = read_chat(&scrstr)) != NULL) {
478fe552114SDavid Nugent                         int i = r = 0;
479fe552114SDavid Nugent 			int off = 0;
480fe552114SDavid Nugent                         sig_t old_alarm;
481fe552114SDavid Nugent 
48226015440SDavid Nugent                         /*
48326015440SDavid Nugent 			 * We need to be in raw mode for all this
48426015440SDavid Nugent 			 * Rely on caller...
485fe552114SDavid Nugent                          */
486fe552114SDavid Nugent 
487fe552114SDavid Nugent                         old_alarm = signal(SIGALRM, chat_alrm);
488fe552114SDavid Nugent                         chat_unalarm(); /* Force blocking mode at start */
489fe552114SDavid Nugent 
490fe552114SDavid Nugent 			/*
491fe552114SDavid Nugent 			 * This is the send/expect loop
492fe552114SDavid Nugent 			 */
493fe552114SDavid Nugent                         while (r == 0 && script[i] != NULL)
494fe552114SDavid Nugent 				if ((r = chat_expect(script[i++])) == 0 && script[i] != NULL)
495fe552114SDavid Nugent 					r = chat_send(script[i++]);
496fe552114SDavid Nugent 
497fe552114SDavid Nugent                         signal(SIGALRM, old_alarm);
498fe552114SDavid Nugent                         free(script);
499fe552114SDavid Nugent                         free(scrstr);
500fe552114SDavid Nugent 
50126015440SDavid Nugent 			/*
50226015440SDavid Nugent 			 * Ensure stdin is in blocking mode
503fe552114SDavid Nugent 			 */
504fe552114SDavid Nugent                         ioctl(STDIN_FILENO, FIONBIO, &off);
505fe552114SDavid Nugent                 }
506fe552114SDavid Nugent 
507fe552114SDavid Nugent                 if (chat_debug & CHATDEBUG_MISC)
508fe552114SDavid Nugent                   syslog(LOG_DEBUG, "getty_chat %s", result(r));
509fe552114SDavid Nugent 
510fe552114SDavid Nugent         }
511fe552114SDavid Nugent         return r;
512fe552114SDavid Nugent }
513