1
0
mirror of https://github.com/UzixLS/picocom.git synced 2025-07-19 07:21:18 +03:00

Corrected, cleaned-up error reporting & handling

This commit is contained in:
Nick Patavalis
2018-03-01 16:40:55 +02:00
parent 31127a5ea7
commit 3e1a610acb
5 changed files with 227 additions and 360 deletions

View File

@ -1504,12 +1504,12 @@ loop(void)
do {
n = term_read(tty_fd, &buff_rd, sizeof(buff_rd));
} while (n < 0 && errno == EINTR);
} while (n < 0 && term_esys() == EINTR);
if (n == 0) {
fatal("read zero bytes from port");
fatal("term_read: Zero bytes from port");
} else if ( n < 0 ) {
if ( errno != EAGAIN && errno != EWOULDBLOCK )
fatal("read from port failed: %s", strerror(errno));
if ( term_esys() != EAGAIN && term_esys() != EWOULDBLOCK )
fatal("term_read: %s", term_strerror(term_errno, errno));
} else {
int i;
char *bmp = &buff_map[0];
@ -1533,9 +1533,9 @@ loop(void)
sz = (tty_q.len < tty_write_sz) ? tty_q.len : tty_write_sz;
do {
n = term_write(tty_fd, tty_q.buff, sz);
} while ( n < 0 && errno == EINTR );
} while ( n < 0 && term_esys() == EINTR );
if ( n <= 0 )
fatal("write to port failed: %s", strerror(errno));
fatal("term_write: %s", term_strerror(term_errno, errno));
if ( opts.lecho && opts.log_filename )
if ( writen_ni(log_fd, tty_q.buff, n) < n )
fatal("write to logfile failed: %s", strerror(errno));

438
term.c
View File

@ -111,7 +111,11 @@ local_init(struct term_s *t)
static int
local_tcgetattr(struct term_s *t, struct termios *termios_out)
{
return tcgetattr(t->fd, termios_out);
int r;
r = tcgetattr(t->fd, termios_out);
if ( r < 0 ) term_errno = TERM_EGETATTR;
return r;
}
static int
@ -122,7 +126,7 @@ local_tcsetattr(struct term_s *t, int when, const struct termios *termios)
do {
r = tcsetattr(t->fd, when, termios);
} while ( r < 0 && errno == EINTR );
if ( r < 0 ) term_errno = TERM_ESETATTR;
return r;
}
@ -131,19 +135,31 @@ local_tcsetattr(struct term_s *t, int when, const struct termios *termios)
static int
local_modem_get(struct term_s *t, int *modem_out)
{
return ioctl(t->fd, TIOCMGET, modem_out);
int r;
r = ioctl(t->fd, TIOCMGET, modem_out);
if ( r < 0 ) term_errno = TERM_EGETMCTL;
return r;
}
static int
local_modem_bis(struct term_s *t, const int *modem)
{
return ioctl(t->fd, TIOCMBIS, modem);
int r;
r = ioctl(t->fd, TIOCMBIS, modem);
if ( r < 0 ) term_errno = TERM_ESETMCTL;
return r;
}
static int
local_modem_bic(struct term_s *t, const int *modem)
{
return ioctl(t->fd, TIOCMBIC, modem);
int r;
r = ioctl(t->fd, TIOCMBIC, modem);
if ( r < 0 ) term_errno = TERM_ESETMCTL;
return r;
}
#endif /* of USE_IOCTL */
@ -155,27 +171,31 @@ local_send_break(struct term_s *t)
do {
r = tcsendbreak(t->fd, 0);
} while (r < 0 && errno == EINTR );
if ( r < 0 ) term_errno = TERM_EBREAK;
return r;
}
static int
local_flush(struct term_s *t, int selector)
{
return tcflush(t->fd, selector);
int r;
r = tcflush(t->fd, selector);
if ( r < 0 ) term_errno = TERM_EFLUSH;
return r;
}
static int
local_fake_flush(struct term_s *t)
{
struct termios tio, tio_orig;
int term_errno_hold = 0, errno_hold = 0;
int r, rval = 0;
do { /* dummy */
/* Get current termios */
r = t->ops->tcgetattr(t, &tio);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
break;
}
@ -186,7 +206,6 @@ local_fake_flush(struct term_s *t)
/* Apply termios */
r = t->ops->tcsetattr(t, TCSANOW, &tio);
if ( r < 0 ) {
term_errno = TERM_ESETATTR;
rval = -1;
break;
}
@ -194,20 +213,25 @@ local_fake_flush(struct term_s *t)
complete in finite time. */
r = t->ops->drain(t);
if ( r < 0 ) {
term_errno = TERM_EDRAIN;
term_errno_hold = term_errno;
errno_hold = errno;
rval = -1;
/* continue */
}
/* Reset flow-control to original setting. */
r = t->ops->tcsetattr(t, TCSANOW, &tio_orig);
if ( rval >=0 && r < 0 ) {
term_errno = TERM_ESETATTR;
if ( r < 0 ) {
rval = -1;
/* continue */
break;
}
} while(0);
if ( term_errno_hold ) {
term_errno = term_errno_hold;
errno = errno_hold;
}
return rval;
}
@ -224,8 +248,10 @@ local_drain(struct term_s *t)
r = tcdrain(t->fd);
#endif
} while ( r < 0 && errno == EINTR);
if ( r < 0 )
if ( r < 0 ) {
term_errno = TERM_EDRAIN;
return r;
}
/* Give some time to the UART to transmit everything. Some
systems and / or drivers corrupt the last character(s) if
@ -240,17 +266,24 @@ local_drain(struct term_s *t)
int
local_read(struct term_s *t, void *buf, unsigned bufsz)
{
return read(t->fd, buf, bufsz);
int r;
r = read(t->fd, buf, bufsz);
if ( r < 0 ) term_errno = TERM_EINPUT;
return r;
}
int
local_write(struct term_s *t, const void *buf, unsigned bufsz)
{
return write(t->fd, buf, bufsz);
int r;
r = write(t->fd, buf, bufsz);
if ( r < 0 ) term_errno = TERM_EOUTPUT;
return r;
}
static const struct term_ops local_term_ops = {
.init = local_init,
.fini = NULL,
.tcgetattr = local_tcgetattr,
.tcsetattr = local_tcsetattr,
#ifdef USE_IOCTL
@ -275,79 +308,63 @@ static const struct term_ops local_term_ops = {
int term_errno;
static const char * const term_err_str[] = {
/* Internal errors (no errno) */
[TERM_EOK] = "No error",
[TERM_EMEM] = "Memory allocation failed",
[TERM_EUNSUP] = "Operation not supported",
[TERM_ENOINIT] = "Framework is uninitialized",
[TERM_EFULL] = "Framework is full",
[TERM_ENOTFOUND] = "Filedes not in the framework",
[TERM_EEXISTS] = "Filedes already in the framework",
[TERM_EATEXIT] = "Cannot install atexit handler",
[TERM_EISATTY] = "Filedes is not a tty",
[TERM_EFLUSH] = "Cannot flush the device",
[TERM_EGETATTR] = "Cannot get the device attributes",
[TERM_ESETATTR] = "Cannot set the device attributes",
[TERM_EBAUD] = "Invalid baud rate",
[TERM_ESETOSPEED] = "Cannot set the output speed",
[TERM_ESETISPEED] = "Cannot set the input speed",
[TERM_EGETSPEED] = "Cannot decode speed",
[TERM_EPARITY] = "Invalid parity mode",
[TERM_EDATABITS] = "Invalid number of databits",
[TERM_ESTOPBITS] = "Invalid number of stopbits",
[TERM_EFLOW] = "Invalid flowcontrol mode",
[TERM_EDTRDOWN] = "Cannot lower DTR",
[TERM_EDTRUP] = "Cannot raise DTR",
[TERM_EMCTL] = "Cannot get mctl status",
[TERM_EDRAIN] = "Cannot drain the device",
[TERM_EBREAK] = "Cannot send break sequence",
[TERM_ERTSDOWN] = "Cannot lower RTS",
[TERM_ERTSUP] = "Cannot raise RTS",
[TERM_EDEVINIT] = "Cannot initialize device"
[TERM_ETIMEDOUT] = "Operation timed-out",
[TERM_ERDZERO] = "Read zero bytes",
/* System errors (check errno for more) */
[TERM_EGETATTR] = "Get attributes error",
[TERM_ESETATTR] = "Set attributes error",
[TERM_EFLUSH] = "Flush error",
[TERM_EDRAIN] = "Drain error",
[TERM_EBREAK] = "Break error",
[TERM_ESETOSPEED] = "Set output speed error",
[TERM_ESETISPEED] = "Set input speed error",
[TERM_EGETSPEED] = "Get speed error",
[TERM_EGETMCTL] = "Get mctl status error",
[TERM_ESETMCTL] = "Set mctl status error",
[TERM_EINPUT] = "Input error",
[TERM_EOUTPUT] = "Output error",
[TERM_ESELECT] = "Select error",
};
static char term_err_buff[1024];
int
term_esys (void)
{
return ( term_errno > TERM_EINTEND && term_errno < TERM_EEND ) ? errno : 0;
}
const char *
term_strerror (int terrnum, int errnum)
{
const char *rval;
switch(terrnum) {
case TERM_EFLUSH:
case TERM_EGETATTR:
case TERM_ESETATTR:
case TERM_ESETOSPEED:
case TERM_ESETISPEED:
case TERM_EDRAIN:
case TERM_EBREAK:
case TERM_EDEVINIT:
if ( term_errno > TERM_EINTEND && term_errno < TERM_EEND ) {
snprintf(term_err_buff, sizeof(term_err_buff),
"%s: %s", term_err_str[terrnum], strerror(errnum));
rval = term_err_buff;
break;
case TERM_EOK:
case TERM_ENOINIT:
case TERM_EFULL:
case TERM_ENOTFOUND:
case TERM_EEXISTS:
case TERM_EATEXIT:
case TERM_EISATTY:
case TERM_EBAUD:
case TERM_EPARITY:
case TERM_EDATABITS:
case TERM_ESTOPBITS:
case TERM_EFLOW:
case TERM_EDTRDOWN:
case TERM_EDTRUP:
case TERM_EMCTL:
case TERM_ERTSDOWN:
case TERM_ERTSUP:
} else if ( term_errno >=0 && term_errno < TERM_EINTEND ) {
snprintf(term_err_buff, sizeof(term_err_buff),
"%s", term_err_str[terrnum]);
rval = term_err_buff;
break;
default:
} else
rval = NULL;
break;
}
return rval;
}
@ -583,7 +600,6 @@ term_new (int fd, const char *name, const struct term_ops *ops)
if (ops->init) {
int r = ops->init(rval);
if ( r < 0 ) {
term_errno = TERM_EDEVINIT;
/* Failed to init, abandon allocation */
rval->fd = -1;
if ( rval->name ) {
@ -664,8 +680,8 @@ term_exitfunc (void)
struct term_s *t = &term[i];
if (t->fd == -1)
continue;
term_drain(t->fd);
t->ops->flush(t, TCIFLUSH);
if (t->ops->drain) t->ops->drain(t);
if (t->ops->flush) t->ops->flush(t, TCIFLUSH);
r = t->ops->tcsetattr(t, TCSANOW, &t->origtermios);
if ( r < 0 ) {
const char *tname;
@ -708,7 +724,7 @@ term_lib_init (void)
struct term_s *t = &term[i];
if (t->fd == -1)
continue;
t->ops->flush(t, TCIOFLUSH);
if (t->ops->flush) t->ops->flush(t, TCIOFLUSH);
r = t->ops->tcsetattr(t, TCSANOW, &t->origtermios);
if ( r < 0 ) {
const char *tname;
@ -766,9 +782,8 @@ term_add (int fd, const char *name, const struct term_ops *ops)
r = t->ops->tcgetattr(t, &t->origtermios);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
term_free(t->fd);
rval = -1;
break;
}
@ -834,14 +849,12 @@ term_replace (int oldfd, int newfd)
r = t->ops->tcsetattr(t, TCSANOW, &t->currtermios);
if ( r < 0 ) {
term_errno = TERM_ESETATTR;
rval = -1;
t->fd = oldfd;
break;
}
r = t->ops->tcgetattr(t, &t->currtermios);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
t->fd = oldfd;
break;
@ -870,21 +883,20 @@ term_reset (int fd)
break;
}
r = t->ops->flush(t, TCIOFLUSH);
if ( r < 0 ) {
term_errno = TERM_EFLUSH;
rval = -1;
break;
if ( t->ops->flush ) {
r = t->ops->flush(t, TCIOFLUSH);
if ( r < 0 ) {
rval = -1;
break;
}
}
r = t->ops->tcsetattr(t, TCSANOW, &t->origtermios);
if ( r < 0 ) {
term_errno = TERM_ESETATTR;
rval = -1;
break;
}
r = t->ops->tcgetattr(t, &t->currtermios);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
break;
}
@ -940,7 +952,6 @@ term_refresh (int fd)
r = t->ops->tcgetattr(t, &t->currtermios);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
break;
}
@ -972,13 +983,11 @@ term_apply (int fd, int now)
r = t->ops->tcsetattr(t, when, &t->nexttermios);
if ( r < 0 ) {
term_errno = TERM_ESETATTR;
rval = -1;
break;
}
r = t->ops->tcgetattr(t, &t->nexttermios);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
break;
}
@ -1564,7 +1573,6 @@ term_pulse_dtr (int fd)
r = t->ops->modem_bic(t, &opins);
if ( r < 0 ) {
term_errno = TERM_EDTRDOWN;
rval = -1;
break;
}
@ -1573,7 +1581,6 @@ term_pulse_dtr (int fd)
r = t->ops->modem_bis(t, &opins);
if ( r < 0 ) {
term_errno = TERM_EDTRUP;
rval = -1;
break;
}
@ -1582,7 +1589,6 @@ term_pulse_dtr (int fd)
r = t->ops->tcgetattr(t, &tio);
if ( r < 0 ) {
term_errno = TERM_EGETATTR;
rval = -1;
break;
}
@ -1593,7 +1599,6 @@ term_pulse_dtr (int fd)
cfsetospeed(&tio, B0);
r = t->ops->tcsetattr(t, TCSANOW, &tio);
if ( r < 0 ) {
term_errno = TERM_ESETATTR;
rval = -1;
break;
}
@ -1603,7 +1608,6 @@ term_pulse_dtr (int fd)
r = t->ops->tcsetattr(t, TCSANOW, &tioold);
if ( r < 0 ) {
t->currtermios = tio;
term_errno = TERM_ESETATTR;
rval = -1;
break;
}
@ -1615,150 +1619,27 @@ term_pulse_dtr (int fd)
/***************************************************************************/
int
term_raise_dtr(int fd)
static int
set_pins (int fd, int raise, int pins)
{
int rval;
struct term_s *t;
int (*rol)(struct term_s *, const int *);
rval = 0;
t = term_find(fd);
if ( ! t ) return -1;
do { /* dummy */
rol = raise ? t->ops->modem_bis : t->ops->modem_bic;
if ( ! rol ) {
term_errno = TERM_EUNSUP; return -1;
}
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
if ( t->ops->modem_bis ) {
int r, opins = TIOCM_DTR;
r = t->ops->modem_bis(t, &opins);
if ( r < 0 ) {
term_errno = TERM_EDTRUP;
rval = -1;
break;
}
} else {
term_errno = TERM_EDTRUP;
rval = -1;
}
} while (0);
return rval;
return rol(t, &pins);
}
/***************************************************************************/
int
term_lower_dtr(int fd)
{
int rval;
struct term_s *t;
rval = 0;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
if ( t->ops->modem_bic ) {
int r, opins = TIOCM_DTR;
r = t->ops->modem_bic(t, &opins);
if ( r < 0 ) {
term_errno = TERM_EDTRDOWN;
rval = -1;
break;
}
} else {
term_errno = TERM_EDTRDOWN;
rval = -1;
}
} while (0);
return rval;
}
/***************************************************************************/
int
term_raise_rts(int fd)
{
int rval;
struct term_s *t;
rval = 0;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
if ( t->ops->modem_bis ) {
int r;
int opins = TIOCM_RTS;
r = t->ops->modem_bis(t, &opins);
if ( r < 0 ) {
term_errno = TERM_ERTSUP;
rval = -1;
break;
}
} else {
term_errno = TERM_ERTSUP;
rval = -1;
}
} while (0);
return rval;
}
/***************************************************************************/
int
term_lower_rts(int fd)
{
int rval;
struct term_s *t;
rval = 0;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
if ( t->ops->modem_bic ) {
int r;
int opins = TIOCM_RTS;
r = t->ops->modem_bic(t, &opins);
if ( r < 0 ) {
term_errno = TERM_ERTSDOWN;
rval = -1;
break;
}
} else {
term_errno = TERM_ERTSDOWN;
rval = -1;
}
} while (0);
return rval;
}
int term_raise_dtr(int fd) { return set_pins(fd, 1, TIOCM_DTR); }
int term_lower_dtr(int fd) { return set_pins(fd, 0, TIOCM_DTR); }
int term_raise_rts(int fd) { return set_pins(fd, 1, TIOCM_RTS); }
int term_lower_rts(int fd) { return set_pins(fd, 0, TIOCM_RTS); }
/***************************************************************************/
@ -1799,32 +1680,19 @@ term_get_mctl (int fd)
return mctl;
}
/***************************************************************************/
int
term_drain(int fd)
{
int rval, r;
struct term_s *t;
rval = 0;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
if ( ! t ) return -1;
if ( ! t->ops->drain ) {
term_errno = TERM_EUNSUP; return -1;
}
r = t->ops->drain(t);
if ( r < 0 ) {
term_errno = TERM_EDRAIN;
rval = -1;
break;
}
} while (0);
return rval;
return t->ops->drain(t);
}
/***************************************************************************/
@ -1835,40 +1703,26 @@ term_fake_flush(int fd)
struct term_s *t;
t = term_find(fd);
if ( ! t )
return -1;
if ( ! t ) return -1;
if ( t->ops->fake_flush )
return t->ops->fake_flush(t);
return 0;
if ( ! t->ops->fake_flush ) {
term_errno = TERM_EUNSUP; return -1;
}
return t->ops->fake_flush(t);
}
int
term_flush(int fd)
{
int rval, r;
struct term_s *t;
rval = 0;
t = term_find(fd);
if ( ! t ) return -1;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
r = t->ops->flush(t, TCIOFLUSH);
if ( r < 0 ) {
term_errno = TERM_EFLUSH;
rval = -1;
break;
}
} while (0);
return rval;
if ( ! t->ops->flush ) {
term_errno = TERM_EUNSUP; return -1;
}
return t->ops->flush(t, TCIOFLUSH);
}
/***************************************************************************/
@ -1876,29 +1730,15 @@ term_flush(int fd)
int
term_break(int fd)
{
int rval, r;
struct term_s *t;
rval = 0;
t = term_find(fd);
if ( ! t ) return -1;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
r = t->ops->send_break(t);
if ( r < 0 ) {
term_errno = TERM_EBREAK;
rval = -1;
break;
}
} while (0);
return rval;
if ( ! t->ops->send_break ) {
term_errno = TERM_EUNSUP; return -1;
}
return t->ops->send_break(t);
}
/**************************************************************************/
@ -1906,37 +1746,23 @@ term_break(int fd)
int
term_read (int fd, void *buf, unsigned int bufsz)
{
int rval;
struct term_s *t;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
rval = t->ops->read(t, buf, bufsz);
} while (0);
t = term_find(fd);
if ( ! t ) return -1;
return rval;
return t->ops->read(t, buf, bufsz);
}
int
term_write (int fd, const void *buf, unsigned int bufsz)
{
int rval;
struct term_s *t;
do { /* dummy */
t = term_find(fd);
if ( ! t ) {
rval = -1;
break;
}
rval = t->ops->write(t, buf, bufsz);
} while (0);
t = term_find(fd);
if ( ! t ) return -1;
return rval;
return t->ops->write(t, buf, bufsz);
}

63
term.h
View File

@ -67,14 +67,15 @@
* F term_flush - discard terminal input and output queue contents
* F term_fake_flush - discard terminal input and output queue contents
* F term_break - generate a break condition on a device
* F term_read - read bytes
* F term_write - write bytes
* F term_baud_up - return next higher baudrate
* F term_baud_down - return next lower baudrate
* F term_baud_ok - check if baudrate is valid
* F term_baud_std - check if baudrate is on of our listed standard baudrates
* F term_esys - return errno if error condition reflects system error
* F term_strerror - return a string describing current error condition
* F term_perror - print a string describing the current error condition
* F term_read - read bytes
* F term_write - write bytes
* G term_errno - current error condition of the library
* G parity_str - parity mode names
* G flow_str - flow control mode names
@ -121,40 +122,48 @@
/*
* E term_errno_e
*
* Library error-condition codes. These marked with "see errno"
* correspond to system errors, so it makes sense to also check the
* system's error-condition code (errno) in order to fully determine
* what went wrong.
* Library error-condition codes. These marked with "check errno for
* more" correspond to system errors, so it makes sense to also check
* the system's error-condition code (errno) in order to fully
* determine what went wrong.
*
* See the error strings in "term.c" for a description of each.
*/
enum term_errno_e {
TERM_EOK = 0,
/* Internal errors (no errno) */
TERM_EOK,
TERM_EMEM,
TERM_EUNSUP,
TERM_ENOINIT,
TERM_EFULL,
TERM_ENOTFOUND,
TERM_EEXISTS,
TERM_EATEXIT,
TERM_EISATTY,
TERM_EFLUSH, /* see errno */
TERM_EGETATTR, /* see errno */
TERM_ESETATTR, /* see errno */
TERM_EBAUD,
TERM_ESETOSPEED,
TERM_ESETISPEED,
TERM_EGETSPEED,
TERM_EPARITY,
TERM_EDATABITS,
TERM_ESTOPBITS,
TERM_EFLOW,
TERM_EDTRDOWN,
TERM_EDTRUP,
TERM_EMCTL,
TERM_EDRAIN, /* see errno */
TERM_ETIMEDOUT,
TERM_ERDZERO,
TERM_EINTEND, /* end of internal errors, sentinel */
/* System errors (check errno for more) */
TERM_EGETATTR,
TERM_ESETATTR,
TERM_EFLUSH,
TERM_EDRAIN,
TERM_EBREAK,
TERM_ERTSDOWN,
TERM_ERTSUP,
TERM_EDEVINIT, /* see errno */
TERM_ESETOSPEED,
TERM_ESETISPEED,
TERM_EGETSPEED,
TERM_EGETMCTL,
TERM_ESETMCTL,
TERM_EINPUT,
TERM_EOUTPUT,
TERM_ESELECT,
TERM_EEND /* end of error condes, sentinel */
};
/* E parity_e
@ -237,6 +246,20 @@ extern const char *flow_str[];
/***************************************************************************/
/*
* F term_esys
*
* Return the current system errno value, if the current library error
* condition reflects a system error where errno is applicable;
* returns 0 otherwise. Exmple usage:
*
* do {
* rn = term_read(t, buff, n);
* } while ( rn < 0 && term_esys() == EINTR )
*
*/
int term_esys();
/*
* F term_strerror
*

View File

@ -43,9 +43,13 @@ struct term_s {
/* Operations on a term */
struct term_ops {
int (*init)(struct term_s *t);
/* NULL ok */
void (*fini)(struct term_s *t);
int (*tcgetattr)(struct term_s *t, struct termios *termios_out);
int (*tcsetattr)(struct term_s *t, int when, const struct termios *termios);
/* NULL ok */
int (*modem_get)(struct term_s *t, int *modem_out);
int (*modem_bis)(struct term_s *t, const int *modem);
int (*modem_bic)(struct term_s *t, const int *modem);
@ -53,6 +57,7 @@ struct term_ops {
int (*flush)(struct term_s *t, int selector);
int (*fake_flush)(struct term_s *t);
int (*drain)(struct term_s *t);
int (*read)(struct term_s *t, void *buf, unsigned bufsz);
int (*write)(struct term_s *t, const void *buf, unsigned bufsz);
};

View File

@ -280,8 +280,9 @@ remote_opt(struct term_s *t, unsigned char opt, int want)
if (q->him == want ? NO : YES) {
msg[1] = want ? DO : DONT;
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg )
return -1;
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg ) {
term_errno = TERM_EOUTPUT; return -1;
}
DB(DB_NEG, "[sent: %s %s]\r\n", str_cmd(msg[1]), str_opt(opt));
q->him = want ? WANTYES : WANTNO;
} else if (q->him == WANTNO) {
@ -302,8 +303,9 @@ local_opt(struct term_s *t, unsigned char opt, int want)
if (q->us == want ? NO : YES) {
msg[1] = want ? WILL : WONT;
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg )
return -1;
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg ) {
term_errno = TERM_EOUTPUT; return -1;
}
DB(DB_NEG, "[sent: %s %s]\r\n", str_cmd(msg[1]), str_opt(opt));
q->us = want ? WANTYES : WANTNO;
} else if (q->us == WANTNO) {
@ -412,8 +414,9 @@ recv_opt(struct term_s *t, unsigned char op, unsigned char opt)
if (respond) {
unsigned char msg[3] = { IAC, respond, opt };
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg)
return -1;
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg) {
term_errno = TERM_EOUTPUT; return -1;
}
DB(DB_NEG, "[sent: %s %s]\r\n", str_cmd(respond), str_opt(opt));
}
return check_options_changed(t, opt);
@ -597,13 +600,18 @@ comport_send_cmd(struct term_s *t, unsigned char cmd,
/* assert(cmd != IAC); */
if ( writen_ni(t->fd, msg, sizeof msg) != sizeof msg )
return -1;
goto werror;
if (datalen)
if ( escape_write(t, data, datalen) != datalen )
return -1;
goto werror;
if ( writen_ni(t->fd, end, sizeof end) != sizeof end )
return -1;
goto werror;
return 0;
werror:
term_errno = TERM_EOUTPUT;
return -1;
}
/* Sends a COM-PORT command consisting of a single byte (a common case) */
@ -1015,6 +1023,7 @@ tn2217_init(struct term_s *t)
t->priv = calloc(1, sizeof (struct tn2217_state));
if ( ! t->priv ) {
term_errno = TERM_EMEM;
return -1;
}
@ -1168,12 +1177,6 @@ tn2217_flush(struct term_s *t, int selector)
return comport_send_cmd1(t, COMPORT_PURGE_DATA, val);
}
static int
tn2217_drain(struct term_s *t)
{
return 0;
}
/* Condition: Initial configuration completed. That is: initial
negotiations completed, configuration commands sent, *and*
replies received. To be used with wait_cond(). */
@ -1203,8 +1206,8 @@ cond_comport_start(struct term_s *t)
condition is satisfied (that is, until "cond" returns non-zero), or
until the timeout expires. Returns a positive on success, zero if
read(2) returned zero, and a negative on any other error
(incl. timeoute expiration). On timeout expiration, errno is set to
ETIMEDOUT.*/
(incl. timeoute expiration). On timeout expiration, term_errno is set to
TERM_ETIMEDOUT.*/
static int
wait_cond(struct term_s *t, int (*cond)(struct term_s *t), int tmo_msec)
{
@ -1221,11 +1224,11 @@ wait_cond(struct term_s *t, int (*cond)(struct term_s *t), int tmo_msec)
FD_ZERO(&rdset);
FD_SET(t->fd, &rdset);
r = select(t->fd + 1, &rdset, 0, 0, &tmo_tv);
if ( r < 0 )
return -1;
else if ( r > 0 ) {
if ( r < 0 ) {
term_errno = TERM_ESELECT; return -1;
} else if ( r > 0 ) {
r = read_and_proc(t, &c, 1);
if ( r == 0 || (r < 0 && errno != EAGAIN) )
if ( r == 0 || (r < 0 && term_esys() != EAGAIN) )
return r;
/* discard c */
}
@ -1233,6 +1236,8 @@ wait_cond(struct term_s *t, int (*cond)(struct term_s *t), int tmo_msec)
if ( timercmp(&now, &tmo_abs, <) ) {
timersub(&tmo_abs, &now, &tmo_tv);
} else {
/* Set both term_errno and errno so clients can check either */
term_errno = TERM_ETIMEDOUT;
errno = ETIMEDOUT;
return -1;
}
@ -1252,8 +1257,10 @@ read_and_proc(struct term_s *t, void *buf, unsigned bufsz)
unsigned char *iac;
inlen = read(t->fd, buf, bufsz);
if (inlen <= 0)
if (inlen <= 0) {
if ( inlen < 0 ) term_errno = TERM_EINPUT;
return inlen;
}
in = out = (unsigned char *)buf;
outlen = 0;
@ -1310,7 +1317,9 @@ read_and_proc(struct term_s *t, void *buf, unsigned bufsz)
if (outlen == 0) {
/* If all we processed were TELNET commands, we can't return 0
* because that would falsely indicate an EOF condition. Instead,
* signal EAGAIN. See the article "Worse is Better". */
* signal EAGAIN. See the article "Worse is Better".
*/
term_errno = TERM_EINPUT;
errno = EAGAIN;
outlen = -1;
}
@ -1354,15 +1363,18 @@ escape_write(struct term_s *t, const void *buf, unsigned bufsz)
end = (const unsigned char *)memchr(start, IAC, len);
while (end) {
n = (end - start) + 1;
if ( writen_ni(t->fd, start, n) != n )
return -1;
if ( writen_ni(t->fd, start, n) != n ) {
term_errno = TERM_EOUTPUT; return -1;
}
len -= end - start;
start = end;
end = (const unsigned char *)memchr(start + 1, IAC, len - 1);
}
if ( writen_ni(t->fd, start, len) != len )
if ( writen_ni(t->fd, start, len) != len ) {
term_errno = TERM_EOUTPUT; return -1;
return -1;
}
return bufsz;
}
@ -1382,7 +1394,7 @@ tn2217_write(struct term_s *t, const void *buf, unsigned bufsz)
DBG("tn2217_write WAITING comport_start\r\n");
r = wait_cond(t, cond_comport_start, 5000);
if ( r <= 0 ) {
if ( r == 0 ) errno = EPIPE;
if ( r == 0 ) term_errno = TERM_ERDZERO;
return -1;
}
DBG("tn2217_write GOT comport_start\r\n");
@ -1401,7 +1413,8 @@ const struct term_ops tn2217_ops = {
.modem_bic = tn2217_modem_bic,
.send_break = tn2217_send_break,
.flush = tn2217_flush,
.drain = tn2217_drain,
.fake_flush = NULL,
.drain = NULL,
.read = tn2217_read,
.write = tn2217_write,
};