Improved error handling

Fixes a memory leak and avoids aggressive busy looping when problems
accessing tty device.
This commit is contained in:
Martin Lund 2016-05-08 00:37:27 +02:00
parent 4c59995db8
commit ece9e7f918
5 changed files with 132 additions and 26 deletions

View file

@ -1,14 +1,16 @@
bin_PROGRAMS = tio bin_PROGRAMS = tio
tio_SOURCES = tty.c \ tio_SOURCES = tty.c \
options.c \ options.c \
time.c \ time.c \
main.c \ main.c \
log.c \ log.c \
include/tio/tty.h \ error.c \
include/tio/options.h \ include/tio/tty.h \
include/tio/time.h \ include/tio/options.h \
include/tio/print.h \ include/tio/time.h \
include/tio/log.h include/tio/print.h \
include/tio/log.h \
include/tio/error.h
if ENABLE_BASH_COMPLETION if ENABLE_BASH_COMPLETION
bashcompletiondir=@BASH_COMPLETION_DIR@ bashcompletiondir=@BASH_COMPLETION_DIR@

35
src/error.c Normal file
View file

@ -0,0 +1,35 @@
/*
* tio - the simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "tio/options.h"
#include "tio/print.h"
char *error = "";
void error_exit(void)
{
if ((error[0] != 0) && (option.no_autoconnect))
printf("Error: %s\n", error);
}

32
src/include/tio/error.h Normal file
View file

@ -0,0 +1,32 @@
/*
* tio - the simple TTY terminal I/O application
*
* Copyright (c) 2014-2016 Martin Lund
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef ERROR_H
#define ERROR_H
#define TIO_SUCCESS 0
#define TIO_ERROR 1
extern char *error;
void error_exit(void);
#endif

View file

@ -21,9 +21,12 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include "tio/options.h" #include "tio/options.h"
#include "tio/tty.h" #include "tio/tty.h"
#include "tio/log.h" #include "tio/log.h"
#include "tio/error.h"
#include "tio/print.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -35,6 +38,9 @@ int main(int argc, char *argv[])
/* Configure output terminal */ /* Configure output terminal */
configure_stdout(); configure_stdout();
/* Install error exit handler */
atexit(&error_exit);
/* Install log exit handler */ /* Install log exit handler */
atexit(&log_exit); atexit(&log_exit);

View file

@ -36,6 +36,7 @@
#include "tio/options.h" #include "tio/options.h"
#include "tio/time.h" #include "tio/time.h"
#include "tio/log.h" #include "tio/log.h"
#include "tio/error.h"
static int connected = false; static int connected = false;
struct termios new_stdout, old_stdout, old_tio; struct termios new_stdout, old_stdout, old_tio;
@ -44,22 +45,27 @@ static bool tainted = false;
void wait_for_tty_device(void) void wait_for_tty_device(void)
{ {
int ready, n;
struct stat status;
fd_set rdfs; fd_set rdfs;
int ready, status;
struct timeval tv; struct timeval tv;
char c_stdin[3]; static char c_stdin[3];
static bool first = true;
/* Loop until device pops up */ /* Loop until device pops up */
while (true) while (true)
{ {
/* Test for accessible device file */ if (first)
if (access(option.tty_device, R_OK) == 0) {
return; /* Don't wait first time */
tv.tv_sec = 0;
/* Wait up to 1 second */ tv.tv_usec = 1;
tv.tv_sec = 1; first = false;
tv.tv_usec = 0; } else
{
/* Wait up to 1 second */
tv.tv_sec = 1;
tv.tv_usec = 0;
}
FD_ZERO(&rdfs); FD_ZERO(&rdfs);
FD_SET(STDIN_FILENO, &rdfs); FD_SET(STDIN_FILENO, &rdfs);
@ -71,7 +77,9 @@ void wait_for_tty_device(void)
/* Input from stdin ready */ /* Input from stdin ready */
/* Read one character */ /* Read one character */
n = read(STDIN_FILENO, &c_stdin[0], 1); status = read(STDIN_FILENO, &c_stdin[0], 1);
if (status < 0)
printf("Warning: Could not read from stdin\n");
/* Exit upon ctrl-t + q sequence */ /* Exit upon ctrl-t + q sequence */
c_stdin[2] = c_stdin[1]; c_stdin[2] = c_stdin[1];
@ -79,6 +87,10 @@ void wait_for_tty_device(void)
if ((c_stdin[1] == KEY_Q) && (c_stdin[2] == KEY_CTRL_T)) if ((c_stdin[1] == KEY_Q) && (c_stdin[2] == KEY_CTRL_T))
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
/* Test for accessible device file */
if (access(option.tty_device, R_OK) == 0)
return;
} }
} }
@ -139,18 +151,24 @@ int connect_tty(void)
fd_set rdfs; /* Read file descriptor set */ fd_set rdfs; /* Read file descriptor set */
int maxfd; /* Maximum file descriptor used */ int maxfd; /* Maximum file descriptor used */
static bool first = true; static bool first = true;
int status;
char c_tty; char c_tty;
char c_stdin[3]; char c_stdin[3];
int status;
/* Open tty device */ /* Open tty device */
fd = open(option.tty_device, O_RDWR | O_NOCTTY ); fd = open(option.tty_device, O_RDWR | O_NOCTTY );
if (fd < 0) if (fd < 0)
return EXIT_FAILURE; {
error = strerror(errno);
goto error_open;
}
/* Make sure device is of tty type */ /* Make sure device is of tty type */
if (!isatty(fd)) if (!isatty(fd))
return EXIT_FAILURE; {
error = "Not a tty device";
goto error_isatty;
}
/* Flush stale I/O data (if any) */ /* Flush stale I/O data (if any) */
tcflush(fd, TCIOFLUSH); tcflush(fd, TCIOFLUSH);
@ -164,7 +182,7 @@ int connect_tty(void)
/* Save current port settings */ /* Save current port settings */
if (tcgetattr(fd, &old_tio) < 0) if (tcgetattr(fd, &old_tio) < 0)
return EXIT_FAILURE; goto error_tcgetattr;
/* Make sure we restore tty settings on exit */ /* Make sure we restore tty settings on exit */
if (first) if (first)
@ -216,13 +234,16 @@ int connect_tty(void)
{ {
/* Error reading - device is likely unplugged */ /* Error reading - device is likely unplugged */
disconnect_tty(); disconnect_tty();
return EXIT_FAILURE; goto error_reading;
} }
} }
if (FD_ISSET(STDIN_FILENO, &rdfs)) if (FD_ISSET(STDIN_FILENO, &rdfs))
{ {
/* Input from stdin ready */ /* Input from stdin ready */
status = read(STDIN_FILENO, &c_stdin[0], 1); status = read(STDIN_FILENO, &c_stdin[0], 1);
if (status < 0)
printf("Warning: Could not read from stdin");
if ((c_stdin[0] != KEY_Q) && (c_stdin[0] != KEY_CTRL_T)) if ((c_stdin[0] != KEY_Q) && (c_stdin[0] != KEY_CTRL_T))
tainted = true; tainted = true;
@ -234,6 +255,8 @@ int connect_tty(void)
/* Forward input to tty device */ /* Forward input to tty device */
status = write(fd, &c_stdin[0], 1); status = write(fd, &c_stdin[0], 1);
if (status < 0)
printf("Warning: Could not write to tty device");
/* Write to log */ /* Write to log */
if (option.log) if (option.log)
@ -245,5 +268,13 @@ int connect_tty(void)
} }
} }
return EXIT_SUCCESS; return TIO_SUCCESS;
error_tcgetattr:
error_isatty:
close(fd);
connected = false;
error_reading:
error_open:
return TIO_ERROR;
} }