chat: update by Vladimir

1) to treat timeout more correctly (timeout affects whole send command
    duration, not a single char); 
 2) to recognize RECORD directive.

function                                             old     new   delta
chat_main                                           1246    1359    +113
exitcode                                               1       -      -1
This commit is contained in:
Denis Vlasenko 2009-03-16 23:06:23 +00:00
parent 074c9036b2
commit 99d71da1cf

View File

@ -9,16 +9,6 @@
*/ */
#include "libbb.h" #include "libbb.h"
/*
#define ENABLE_FEATURE_CHAT_NOFAIL 1 // +126 bytes
#define ENABLE_FEATURE_CHAT_TTY_HIFI 0 // + 70 bytes
#define ENABLE_FEATURE_CHAT_IMPLICIT_CR 1 // + 44 bytes
#define ENABLE_FEATURE_CHAT_SEND_ESCAPES 0 // +103 bytes
#define ENABLE_FEATURE_CHAT_VAR_ABORT_LEN 0 // + 70 bytes
#define ENABLE_FEATURE_CHAT_CLR_ABORT 0 // +113 bytes
#define ENABLE_FEATURE_CHAT_SWALLOW_OPTS 0 // + 23 bytes
*/
// default timeout: 45 sec // default timeout: 45 sec
#define DEFAULT_CHAT_TIMEOUT 45*1000 #define DEFAULT_CHAT_TIMEOUT 45*1000
// max length of "abort string", // max length of "abort string",
@ -37,8 +27,7 @@ enum {
}; };
// exit code // exit code
// N.B> 10 bytes for volatile. Why all these signals?! #define exitcode bb_got_signal
static /*volatile*/ smallint exitcode;
// trap for critical signals // trap for critical signals
static void signal_handler(UNUSED_PARAM int signo) static void signal_handler(UNUSED_PARAM int signo)
@ -101,13 +90,10 @@ static size_t unescape(char *s, int *nocr)
return p - start; return p - start;
} }
int chat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int chat_main(int argc UNUSED_PARAM, char **argv) int chat_main(int argc UNUSED_PARAM, char **argv)
{ {
// should we dump device output? to what fd? by default no. int record_fd = -1;
// this can be controlled later via ECHO {ON|OFF} chat directive
// int echo_fd;
bool echo = 0; bool echo = 0;
// collection of device replies which cause unconditional termination // collection of device replies which cause unconditional termination
llist_t *aborts = NULL; llist_t *aborts = NULL;
@ -132,6 +118,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
DIR_TIMEOUT, DIR_TIMEOUT,
DIR_ECHO, DIR_ECHO,
DIR_SAY, DIR_SAY,
DIR_RECORD,
}; };
// make x* functions fail with correct exitcode // make x* functions fail with correct exitcode
@ -166,14 +153,14 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_CHAT_CLR_ABORT #if ENABLE_FEATURE_CHAT_CLR_ABORT
"CLR_ABORT\0" "CLR_ABORT\0"
#endif #endif
"TIMEOUT\0" "ECHO\0" "SAY\0" "TIMEOUT\0" "ECHO\0" "SAY\0" "RECORD\0"
, *argv , *argv
); );
if (key >= 0) { if (key >= 0) {
// cache directive value // cache directive value
char *arg = *++argv; char *arg = *++argv;
// ON -> 1, anything else -> 0 // OFF -> 0, anything else -> 1
bool onoff = !strcmp("ON", arg); bool onoff = (0 != strcmp("OFF", arg));
// process directive // process directive
if (DIR_HANGUP == key) { if (DIR_HANGUP == key) {
// turn SIGHUP on/off // turn SIGHUP on/off
@ -217,14 +204,20 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
timeout = DEFAULT_CHAT_TIMEOUT; timeout = DEFAULT_CHAT_TIMEOUT;
} else if (DIR_ECHO == key) { } else if (DIR_ECHO == key) {
// turn echo on/off // turn echo on/off
// N.B. echo means dumping output // N.B. echo means dumping device input/output to stderr
// from stdin (device) to stderr
echo = onoff; echo = onoff;
//TODO? echo_fd = onoff * STDERR_FILENO; } else if (DIR_RECORD == key) {
//TODO? echo_fd = xopen(arg, O_WRONLY|O_CREAT|O_TRUNC); // turn record on/off
// N.B. record means dumping device input to a file
// close previous record_fd
if (record_fd > 0)
close(record_fd);
// N.B. do we have to die here on open error?
record_fd = (onoff) ? xopen(arg, O_WRONLY|O_CREAT|O_TRUNC) : -1;
} else if (DIR_SAY == key) { } else if (DIR_SAY == key) {
// just print argument verbatim // just print argument verbatim
fprintf(stderr, arg); // TODO: should we use full_write() to avoid unistd/stdio conflict?
bb_error_msg("%s", arg);
} }
// next, please! // next, please!
argv++; argv++;
@ -288,12 +281,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
// read next char from device // read next char from device
if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) { if (safe_read(STDIN_FILENO, buf+buf_len, 1) > 0) {
// dump device output if ECHO ON or RECORD fname // dump device input if RECORD fname
//TODO? if (echo_fd > 0) { if (record_fd > 0) {
//TODO? full_write(echo_fd, buf+buf_len, 1); full_write(record_fd, buf+buf_len, 1);
//TODO? } }
if (echo > 0) // dump device input if ECHO ON
if (echo > 0) {
// if (buf[buf_len] < ' ') {
// full_write(STDERR_FILENO, "^", 1);
// buf[buf_len] += '@';
// }
full_write(STDERR_FILENO, buf+buf_len, 1); full_write(STDERR_FILENO, buf+buf_len, 1);
}
buf_len++; buf_len++;
// move input frame if we've reached higher bound // move input frame if we've reached higher bound
if (buf_len > COMMON_BUFSIZE) { if (buf_len > COMMON_BUFSIZE) {
@ -320,7 +319,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
if (delta >= 0 && !memcmp(buf+delta, expect, expect_len)) if (delta >= 0 && !memcmp(buf+delta, expect, expect_len))
goto expect_done; goto expect_done;
#undef buf #undef buf
} } /* while (have data) */
// device timed out or unexpected reply received // device timed out or unexpected reply received
exitcode = ERR_TIMEOUT; exitcode = ERR_TIMEOUT;
@ -365,21 +364,18 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
trim(++buf); trim(++buf);
buf = loaded = xmalloc_xopen_read_close(buf, NULL); buf = loaded = xmalloc_xopen_read_close(buf, NULL);
} }
// expand escape sequences in command // expand escape sequences in command
len = unescape(buf, &nocr); len = unescape(buf, &nocr);
// send command // send command
#if ENABLE_FEATURE_CHAT_SEND_ESCAPES alarm(timeout);
pfd.fd = STDOUT_FILENO; pfd.fd = STDOUT_FILENO;
pfd.events = POLLOUT; pfd.events = POLLOUT;
while (len && !exitcode while (len && !exitcode
&& poll(&pfd, 1, timeout) > 0 && poll(&pfd, 1, -1) > 0
&& (pfd.revents & POLLOUT) && (pfd.revents & POLLOUT)
) { ) {
// ugly! ugly! ugly! #if ENABLE_FEATURE_CHAT_SEND_ESCAPES
// gotta send char by char to achieve this!
// Brrr...
// "\\d" means 1 sec delay, "\\p" means 0.01 sec delay // "\\d" means 1 sec delay, "\\p" means 0.01 sec delay
// "\\K" means send BREAK // "\\K" means send BREAK
char c = *buf; char c = *buf;
@ -389,31 +385,28 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
sleep(1); sleep(1);
len--; len--;
continue; continue;
} else if ('p' == c) { }
if ('p' == c) {
usleep(10000); usleep(10000);
len--; len--;
continue; continue;
} else if ('K' == c) { }
if ('K' == c) {
tcsendbreak(STDOUT_FILENO, 0); tcsendbreak(STDOUT_FILENO, 0);
len--; len--;
continue; continue;
} else { }
buf--; buf--;
} }
} if (safe_write(STDOUT_FILENO, buf, 1) != 1)
if (safe_write(STDOUT_FILENO, buf, 1) > 0) { break;
len--; len--;
buf++; buf++;
} else
break;
}
#else #else
// if (len) {
alarm(timeout);
len -= full_write(STDOUT_FILENO, buf, len); len -= full_write(STDOUT_FILENO, buf, len);
alarm(0);
// }
#endif #endif
} /* while (can write) */
alarm(0);
// report I/O error if there still exists at least one non-sent char // report I/O error if there still exists at least one non-sent char
if (len) if (len)
@ -427,14 +420,12 @@ int chat_main(int argc UNUSED_PARAM, char **argv)
else if (!nocr) else if (!nocr)
xwrite(STDOUT_FILENO, "\r", 1); xwrite(STDOUT_FILENO, "\r", 1);
#endif #endif
// bail out unless we sent command successfully // bail out unless we sent command successfully
if (exitcode) if (exitcode)
break; break;
} /* if (*argv) */
}
}
} }
} /* while (*argv) */
#if ENABLE_FEATURE_CHAT_TTY_HIFI #if ENABLE_FEATURE_CHAT_TTY_HIFI
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0); tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio0);