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