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:
12
picocom.c
12
picocom.c
@ -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
438
term.c
@ -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
63
term.h
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
};
|
||||
|
69
tn2217.c
69
tn2217.c
@ -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,
|
||||
};
|
||||
|
Reference in New Issue
Block a user