mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add support for external control via a Unix domain socket.
This feature allows an external program to inject output into and listen to input from a serial port via a Unix domain socket (path specified via the -S/--socket command line flag, or the socket config file option) while tio is running. This is useful for ad-hoc scripting of serial port interactions while still permitting manual control. Since many serial devices (at least on Linux) get confused when opened by multiple processes, and most commands do not know how to correctly open a serial device, this allows a more convenient usage model than directly writing to the device node from an external program. Any input from clients connected to the socket is sent on the serial port as if entered at the terminal where tio is running (except that ctrl-t sequences are not recognized), and any input from the serial port is multiplexed to the terminal and all connected clients. Sockets remain open while the serial port is disconnected, and writes will block. Example usage 1 (issue a command): echo command | nc -UN /path/to/socket > /dev/null Example usage 2 (use the expect command to script an interaction): #!/usr/bin/expect -f set timeout -1 log_user 0 spawn nc -UN /path/to/socket set uart $spawn_id send -i $uart "command1\n" expect -i $uart "prompt> " send -i $uart "command2\n" expect -i $uart "prompt> "
This commit is contained in:
parent
03e41b61a3
commit
fb453160ef
11 changed files with 335 additions and 57 deletions
125
src/tty.c
125
src/tty.c
|
|
@ -31,6 +31,8 @@
|
|||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <stdbool.h>
|
||||
|
|
@ -45,6 +47,7 @@
|
|||
#include "misc.h"
|
||||
#include "log.h"
|
||||
#include "error.h"
|
||||
#include "socket.h"
|
||||
|
||||
#ifdef HAVE_TERMIOS2
|
||||
extern int setspeed2(int fd, int baudrate);
|
||||
|
|
@ -494,6 +497,7 @@ void tty_wait_for_device(void)
|
|||
{
|
||||
fd_set rdfs;
|
||||
int status;
|
||||
int maxfd;
|
||||
struct timeval tv;
|
||||
static char input_char, previous_char = 0;
|
||||
static bool first = true;
|
||||
|
|
@ -517,26 +521,30 @@ void tty_wait_for_device(void)
|
|||
|
||||
FD_ZERO(&rdfs);
|
||||
FD_SET(STDIN_FILENO, &rdfs);
|
||||
maxfd = MAX(STDIN_FILENO, socket_add_fds(&rdfs, false));
|
||||
|
||||
/* Block until input becomes available or timeout */
|
||||
status = select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv);
|
||||
status = select(maxfd + 1, &rdfs, NULL, NULL, &tv);
|
||||
if (status > 0)
|
||||
{
|
||||
/* Input from stdin ready */
|
||||
|
||||
/* Read one character */
|
||||
status = read(STDIN_FILENO, &input_char, 1);
|
||||
if (status <= 0)
|
||||
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
||||
{
|
||||
error_printf("Could not read from stdin");
|
||||
exit(EXIT_FAILURE);
|
||||
/* Input from stdin ready */
|
||||
|
||||
/* Read one character */
|
||||
status = read(STDIN_FILENO, &input_char, 1);
|
||||
if (status <= 0)
|
||||
{
|
||||
error_printf("Could not read from stdin");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle commands */
|
||||
handle_command_sequence(input_char, previous_char, NULL, NULL);
|
||||
|
||||
previous_char = input_char;
|
||||
}
|
||||
|
||||
/* Handle commands */
|
||||
handle_command_sequence(input_char, previous_char, NULL, NULL);
|
||||
|
||||
previous_char = input_char;
|
||||
|
||||
socket_handle_input(&rdfs, NULL);
|
||||
} else if (status == -1)
|
||||
{
|
||||
error_printf("select() failed (%s)", strerror(errno));
|
||||
|
|
@ -686,19 +694,20 @@ int tty_connect(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
maxfd = MAX(fd, STDIN_FILENO) + 1; /* Maximum bit entry (fd) to test */
|
||||
|
||||
/* Input loop */
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rdfs);
|
||||
FD_SET(fd, &rdfs);
|
||||
FD_SET(STDIN_FILENO, &rdfs);
|
||||
maxfd = MAX(fd, STDIN_FILENO);
|
||||
maxfd = MAX(maxfd, socket_add_fds(&rdfs, true));
|
||||
|
||||
/* Block until input becomes available */
|
||||
status = select(maxfd, &rdfs, NULL, NULL, NULL);
|
||||
status = select(maxfd + 1, &rdfs, NULL, NULL, NULL);
|
||||
if (status > 0)
|
||||
{
|
||||
bool forward = false;
|
||||
if (FD_ISSET(fd, &rdfs))
|
||||
{
|
||||
/* Input from tty device ready */
|
||||
|
|
@ -747,6 +756,8 @@ int tty_connect(void)
|
|||
if (option.log)
|
||||
log_write(input_char);
|
||||
|
||||
socket_write(input_char);
|
||||
|
||||
print_tainted = true;
|
||||
|
||||
if (input_char == '\n' && option.timestamp)
|
||||
|
|
@ -760,7 +771,7 @@ int tty_connect(void)
|
|||
}
|
||||
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
||||
{
|
||||
bool forward = true;
|
||||
forward = true;
|
||||
|
||||
/* Input from stdin ready */
|
||||
status = read(STDIN_FILENO, &input_char, 1);
|
||||
|
|
@ -778,47 +789,51 @@ int tty_connect(void)
|
|||
/* Handle commands */
|
||||
handle_command_sequence(input_char, previous_char, &output_char, &forward);
|
||||
|
||||
if (forward)
|
||||
{
|
||||
/* Map output character */
|
||||
if ((output_char == 127) && (map_o_del_bs))
|
||||
output_char = '\b';
|
||||
if ((output_char == '\r') && (map_o_cr_nl))
|
||||
output_char = '\n';
|
||||
|
||||
/* Map newline character */
|
||||
if ((output_char == '\n' || output_char == '\r') && (map_o_nl_crnl)) {
|
||||
const char *crlf = "\r\n";
|
||||
|
||||
optional_local_echo(crlf[0]);
|
||||
optional_local_echo(crlf[1]);
|
||||
status = write(fd, crlf, 2);
|
||||
if (status < 0)
|
||||
warning_printf("Could not write to tty device");
|
||||
|
||||
tx_total += 2;
|
||||
delay(option.output_delay);
|
||||
} else
|
||||
{
|
||||
/* Send output to tty device */
|
||||
optional_local_echo(output_char);
|
||||
status = write(fd, &output_char, 1);
|
||||
if (status < 0)
|
||||
warning_printf("Could not write to tty device");
|
||||
fsync(fd);
|
||||
|
||||
/* Update transmit statistics */
|
||||
tx_total++;
|
||||
|
||||
/* Insert output delay */
|
||||
delay(option.output_delay);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save previous key */
|
||||
previous_char = input_char;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
forward = socket_handle_input(&rdfs, &output_char);
|
||||
}
|
||||
|
||||
if (forward)
|
||||
{
|
||||
/* Map output character */
|
||||
if ((output_char == 127) && (map_o_del_bs))
|
||||
output_char = '\b';
|
||||
if ((output_char == '\r') && (map_o_cr_nl))
|
||||
output_char = '\n';
|
||||
|
||||
/* Map newline character */
|
||||
if ((output_char == '\n' || output_char == '\r') && (map_o_nl_crnl)) {
|
||||
const char *crlf = "\r\n";
|
||||
|
||||
optional_local_echo(crlf[0]);
|
||||
optional_local_echo(crlf[1]);
|
||||
status = write(fd, crlf, 2);
|
||||
if (status < 0)
|
||||
warning_printf("Could not write to tty device");
|
||||
|
||||
tx_total += 2;
|
||||
delay(option.output_delay);
|
||||
} else
|
||||
{
|
||||
/* Send output to tty device */
|
||||
optional_local_echo(output_char);
|
||||
status = write(fd, &output_char, 1);
|
||||
if (status < 0)
|
||||
warning_printf("Could not write to tty device");
|
||||
fsync(fd);
|
||||
|
||||
/* Update transmit statistics */
|
||||
tx_total++;
|
||||
|
||||
/* Insert output delay */
|
||||
delay(option.output_delay);
|
||||
}
|
||||
}
|
||||
} else if (status == -1)
|
||||
{
|
||||
error_printf("Error: select() failed (%s)", strerror(errno));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue