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
14
man/tio.1.in
14
man/tio.1.in
|
|
@ -114,6 +114,17 @@ Colorize tio text using ANSI color code ranging from 0 to 255.
|
||||||
|
|
||||||
If color code is negative a list of available ANSI colors will be printed.
|
If color code is negative a list of available ANSI colors will be printed.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR \-S ", " "\-\-socket unix:\fI<filename>\fR\fB
|
||||||
|
|
||||||
|
Listen on a Unix domain socket at the specified path. 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
|
||||||
|
.B 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.
|
||||||
|
|
||||||
|
At present there is a hardcoded limit of 16 clients connected at one time.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-v ", " \-\-version
|
.BR \-v ", " \-\-version
|
||||||
|
|
||||||
|
|
@ -201,6 +212,9 @@ Set log filename
|
||||||
Map special characters on input or output
|
Map special characters on input or output
|
||||||
.IP "\fBcolor"
|
.IP "\fBcolor"
|
||||||
Colorize tio text using ANSI color code ranging from 0 to 255.
|
Colorize tio text using ANSI color code ranging from 0 to 255.
|
||||||
|
.IP "\fBsocket"
|
||||||
|
Set socket path (must include
|
||||||
|
.BR unix: ).
|
||||||
|
|
||||||
.SH "CONFIGURATION EXAMPLES"
|
.SH "CONFIGURATION EXAMPLES"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@ _tio()
|
||||||
COMPREPLY=( $(compgen -W "$(seq 0 255)" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "$(seq 0 255)" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
-S | --socket)
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
-v | --version)
|
-v | --version)
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,11 @@ static int data_handler(void *user, const char *section, const char *name,
|
||||||
{
|
{
|
||||||
option.color = atoi(value);
|
option.color = atoi(value);
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(name, "socket"))
|
||||||
|
{
|
||||||
|
asprintf(&c->socket, "%s", value);
|
||||||
|
option.socket = c->socket;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ struct config_t
|
||||||
char *flow;
|
char *flow;
|
||||||
char *parity;
|
char *parity;
|
||||||
char *log_filename;
|
char *log_filename;
|
||||||
|
char *socket;
|
||||||
char *map;
|
char *map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "signals.h"
|
#include "signals.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
@ -71,6 +72,9 @@ int main(int argc, char *argv[])
|
||||||
if (option.log)
|
if (option.log)
|
||||||
log_open(option.log_filename);
|
log_open(option.log_filename);
|
||||||
|
|
||||||
|
/* Open socket */
|
||||||
|
socket_configure();
|
||||||
|
|
||||||
/* Enable ANSI text formatting (colors etc.) */
|
/* Enable ANSI text formatting (colors etc.) */
|
||||||
print_enable_ansi_formatting();
|
print_enable_ansi_formatting();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@ tio_sources = [
|
||||||
'tty.c',
|
'tty.c',
|
||||||
'print.c',
|
'print.c',
|
||||||
'configfile.c',
|
'configfile.c',
|
||||||
'signals.c'
|
'signals.c',
|
||||||
|
'socket.c'
|
||||||
]
|
]
|
||||||
|
|
||||||
tio_dep = dependency('inih', required: true,
|
tio_dep = dependency('inih', required: true,
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ struct option_t option =
|
||||||
.timestamp = TIMESTAMP_NONE,
|
.timestamp = TIMESTAMP_NONE,
|
||||||
.list_devices = false,
|
.list_devices = false,
|
||||||
.log_filename = "",
|
.log_filename = "",
|
||||||
|
.socket = NULL,
|
||||||
.map = "",
|
.map = "",
|
||||||
.color = -1,
|
.color = -1,
|
||||||
};
|
};
|
||||||
|
|
@ -73,6 +74,7 @@ void print_help(char *argv[])
|
||||||
printf(" -l, --log[=<filename>] Log to file\n");
|
printf(" -l, --log[=<filename>] Log to file\n");
|
||||||
printf(" -m, --map <flags> Map special characters\n");
|
printf(" -m, --map <flags> Map special characters\n");
|
||||||
printf(" -c, --color <code> Colorize tio text\n");
|
printf(" -c, --color <code> Colorize tio text\n");
|
||||||
|
printf(" -S, --socket <filename> Listen on domain socket\n");
|
||||||
printf(" -v, --version Display version\n");
|
printf(" -v, --version Display version\n");
|
||||||
printf(" -h, --help Display help\n");
|
printf(" -h, --help Display help\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
@ -174,6 +176,7 @@ void options_parse(int argc, char *argv[])
|
||||||
{"timestamp", optional_argument, 0, 't'},
|
{"timestamp", optional_argument, 0, 't'},
|
||||||
{"list-devices", no_argument, 0, 'L'},
|
{"list-devices", no_argument, 0, 'L'},
|
||||||
{"log", optional_argument, 0, 'l'},
|
{"log", optional_argument, 0, 'l'},
|
||||||
|
{"socket", required_argument, 0, 'S'},
|
||||||
{"map", required_argument, 0, 'm'},
|
{"map", required_argument, 0, 'm'},
|
||||||
{"color", required_argument, 0, 'c'},
|
{"color", required_argument, 0, 'c'},
|
||||||
{"version", no_argument, 0, 'v'},
|
{"version", no_argument, 0, 'v'},
|
||||||
|
|
@ -185,7 +188,7 @@ void options_parse(int argc, char *argv[])
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
|
||||||
/* Parse argument using getopt_long */
|
/* Parse argument using getopt_long */
|
||||||
c = getopt_long(argc, argv, "b:d:f:s:p:o:net::Ll::m:c:vh", long_options, &option_index);
|
c = getopt_long(argc, argv, "b:d:f:s:p:o:net::Ll:S::m:c:vh", long_options, &option_index);
|
||||||
|
|
||||||
/* Detect the end of the options */
|
/* Detect the end of the options */
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
|
|
@ -248,6 +251,10 @@ void options_parse(int argc, char *argv[])
|
||||||
option.log_filename = optarg;
|
option.log_filename = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
option.socket = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
option.map = optarg;
|
option.map = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ struct option_t
|
||||||
bool list_devices;
|
bool list_devices;
|
||||||
const char *log_filename;
|
const char *log_filename;
|
||||||
const char *map;
|
const char *map;
|
||||||
|
const char *socket;
|
||||||
int color;
|
int color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
195
src/socket.c
Normal file
195
src/socket.c
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* tio - a simple serial terminal I/O tool
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2022 Martin Lund
|
||||||
|
* Copyright (c) 2022 Google LLC
|
||||||
|
*
|
||||||
|
* 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 "socket.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAX_SOCKET_CLIENTS 16
|
||||||
|
|
||||||
|
static int sockfd;
|
||||||
|
static int clientfds[MAX_SOCKET_CLIENTS];
|
||||||
|
|
||||||
|
static const char *socket_filename(void)
|
||||||
|
{
|
||||||
|
/* skip 'unix:' */
|
||||||
|
return option.socket + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void socket_exit(void)
|
||||||
|
{
|
||||||
|
unlink(socket_filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
void socket_configure(void)
|
||||||
|
{
|
||||||
|
if (!option.socket)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(option.socket, "unix:", 5) != 0)
|
||||||
|
{
|
||||||
|
error_printf("%s: Invalid socket scheme, must be 'unix:'", option.socket);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un sockaddr = {};
|
||||||
|
if (strlen(socket_filename()) > sizeof(sockaddr.sun_path) - 1)
|
||||||
|
{
|
||||||
|
error_printf("Socket file path %s too long", option.socket);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr.sun_family = AF_UNIX;
|
||||||
|
strncpy(sockaddr.sun_path, socket_filename(), sizeof(sockaddr.sun_path) - 1);
|
||||||
|
|
||||||
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
error_printf("Failed to create socket: %s", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(socket_filename());
|
||||||
|
if (bind(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0)
|
||||||
|
{
|
||||||
|
error_printf("Failed to bind to socket %s: %s", socket_filename(), strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sockfd, MAX_SOCKET_CLIENTS) < 0)
|
||||||
|
{
|
||||||
|
error_printf("Failed to listen on socket %s: %s", socket_filename(), strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(clientfds, -1, sizeof(clientfds));
|
||||||
|
atexit(socket_exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void socket_write(char input_char)
|
||||||
|
{
|
||||||
|
if (!option.socket)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
|
||||||
|
{
|
||||||
|
if (clientfds[i] != -1)
|
||||||
|
{
|
||||||
|
if (write(clientfds[i], &input_char, 1) <= 0)
|
||||||
|
{
|
||||||
|
error_printf_silent("Failed to write to socket: %s", strerror(errno));
|
||||||
|
close(clientfds[i]);
|
||||||
|
clientfds[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int socket_add_fds(fd_set *rdfs, bool connected)
|
||||||
|
{
|
||||||
|
if (!option.socket)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numclients = 0, maxfd = 0;
|
||||||
|
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
|
||||||
|
{
|
||||||
|
if (clientfds[i] != -1)
|
||||||
|
{
|
||||||
|
/* let clients block if they try to send while we're disconnected */
|
||||||
|
if (connected)
|
||||||
|
{
|
||||||
|
FD_SET(clientfds[i], rdfs);
|
||||||
|
maxfd = MAX(maxfd, clientfds[i]);
|
||||||
|
}
|
||||||
|
numclients++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* don't bother to accept clients if we're already full */
|
||||||
|
if (numclients != MAX_SOCKET_CLIENTS)
|
||||||
|
{
|
||||||
|
FD_SET(sockfd, rdfs);
|
||||||
|
maxfd = MAX(maxfd, sockfd);
|
||||||
|
}
|
||||||
|
return maxfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool socket_handle_input(fd_set *rdfs, char *output_char)
|
||||||
|
{
|
||||||
|
if (!option.socket)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(sockfd, rdfs))
|
||||||
|
{
|
||||||
|
int clientfd = accept(sockfd, NULL, NULL);
|
||||||
|
/* this loop should always succeed because we don't select on sockfd when full */
|
||||||
|
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
|
||||||
|
{
|
||||||
|
if (clientfds[i] == -1)
|
||||||
|
{
|
||||||
|
clientfds[i] = clientfd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
|
||||||
|
{
|
||||||
|
if (clientfds[i] != -1 && FD_ISSET(clientfds[i], rdfs))
|
||||||
|
{
|
||||||
|
int status = read(clientfds[i], output_char, 1);
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
close(clientfds[i]);
|
||||||
|
clientfds[i] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
error_printf_silent("Failed to read from socket: %s", strerror(errno));
|
||||||
|
close(clientfds[i]);
|
||||||
|
clientfds[i] = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* match the behavior of a terminal in raw mode */
|
||||||
|
if (*output_char == '\n')
|
||||||
|
{
|
||||||
|
*output_char = '\r';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
31
src/socket.h
Normal file
31
src/socket.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* tio - a simple serial terminal I/O tool
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014-2022 Martin Lund
|
||||||
|
* Copyright (c) 2022 Google LLC
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
|
void socket_configure(void);
|
||||||
|
void socket_write(char input_char);
|
||||||
|
int socket_add_fds(fd_set *fds, bool connected);
|
||||||
|
bool socket_handle_input(fd_set *fds, char *output_char);
|
||||||
37
src/tty.c
37
src/tty.c
|
|
@ -31,6 +31,8 @@
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
@ -45,6 +47,7 @@
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "socket.h"
|
||||||
|
|
||||||
#ifdef HAVE_TERMIOS2
|
#ifdef HAVE_TERMIOS2
|
||||||
extern int setspeed2(int fd, int baudrate);
|
extern int setspeed2(int fd, int baudrate);
|
||||||
|
|
@ -494,6 +497,7 @@ void tty_wait_for_device(void)
|
||||||
{
|
{
|
||||||
fd_set rdfs;
|
fd_set rdfs;
|
||||||
int status;
|
int status;
|
||||||
|
int maxfd;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
static char input_char, previous_char = 0;
|
static char input_char, previous_char = 0;
|
||||||
static bool first = true;
|
static bool first = true;
|
||||||
|
|
@ -517,10 +521,13 @@ void tty_wait_for_device(void)
|
||||||
|
|
||||||
FD_ZERO(&rdfs);
|
FD_ZERO(&rdfs);
|
||||||
FD_SET(STDIN_FILENO, &rdfs);
|
FD_SET(STDIN_FILENO, &rdfs);
|
||||||
|
maxfd = MAX(STDIN_FILENO, socket_add_fds(&rdfs, false));
|
||||||
|
|
||||||
/* Block until input becomes available or timeout */
|
/* 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)
|
if (status > 0)
|
||||||
|
{
|
||||||
|
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
||||||
{
|
{
|
||||||
/* Input from stdin ready */
|
/* Input from stdin ready */
|
||||||
|
|
||||||
|
|
@ -536,7 +543,8 @@ void tty_wait_for_device(void)
|
||||||
handle_command_sequence(input_char, previous_char, NULL, NULL);
|
handle_command_sequence(input_char, previous_char, NULL, NULL);
|
||||||
|
|
||||||
previous_char = input_char;
|
previous_char = input_char;
|
||||||
|
}
|
||||||
|
socket_handle_input(&rdfs, NULL);
|
||||||
} else if (status == -1)
|
} else if (status == -1)
|
||||||
{
|
{
|
||||||
error_printf("select() failed (%s)", strerror(errno));
|
error_printf("select() failed (%s)", strerror(errno));
|
||||||
|
|
@ -686,19 +694,20 @@ int tty_connect(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
maxfd = MAX(fd, STDIN_FILENO) + 1; /* Maximum bit entry (fd) to test */
|
|
||||||
|
|
||||||
/* Input loop */
|
/* Input loop */
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
FD_ZERO(&rdfs);
|
FD_ZERO(&rdfs);
|
||||||
FD_SET(fd, &rdfs);
|
FD_SET(fd, &rdfs);
|
||||||
FD_SET(STDIN_FILENO, &rdfs);
|
FD_SET(STDIN_FILENO, &rdfs);
|
||||||
|
maxfd = MAX(fd, STDIN_FILENO);
|
||||||
|
maxfd = MAX(maxfd, socket_add_fds(&rdfs, true));
|
||||||
|
|
||||||
/* Block until input becomes available */
|
/* Block until input becomes available */
|
||||||
status = select(maxfd, &rdfs, NULL, NULL, NULL);
|
status = select(maxfd + 1, &rdfs, NULL, NULL, NULL);
|
||||||
if (status > 0)
|
if (status > 0)
|
||||||
{
|
{
|
||||||
|
bool forward = false;
|
||||||
if (FD_ISSET(fd, &rdfs))
|
if (FD_ISSET(fd, &rdfs))
|
||||||
{
|
{
|
||||||
/* Input from tty device ready */
|
/* Input from tty device ready */
|
||||||
|
|
@ -747,6 +756,8 @@ int tty_connect(void)
|
||||||
if (option.log)
|
if (option.log)
|
||||||
log_write(input_char);
|
log_write(input_char);
|
||||||
|
|
||||||
|
socket_write(input_char);
|
||||||
|
|
||||||
print_tainted = true;
|
print_tainted = true;
|
||||||
|
|
||||||
if (input_char == '\n' && option.timestamp)
|
if (input_char == '\n' && option.timestamp)
|
||||||
|
|
@ -760,7 +771,7 @@ int tty_connect(void)
|
||||||
}
|
}
|
||||||
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
if (FD_ISSET(STDIN_FILENO, &rdfs))
|
||||||
{
|
{
|
||||||
bool forward = true;
|
forward = true;
|
||||||
|
|
||||||
/* Input from stdin ready */
|
/* Input from stdin ready */
|
||||||
status = read(STDIN_FILENO, &input_char, 1);
|
status = read(STDIN_FILENO, &input_char, 1);
|
||||||
|
|
@ -778,6 +789,15 @@ int tty_connect(void)
|
||||||
/* Handle commands */
|
/* Handle commands */
|
||||||
handle_command_sequence(input_char, previous_char, &output_char, &forward);
|
handle_command_sequence(input_char, previous_char, &output_char, &forward);
|
||||||
|
|
||||||
|
/* Save previous key */
|
||||||
|
previous_char = input_char;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forward = socket_handle_input(&rdfs, &output_char);
|
||||||
|
}
|
||||||
|
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
/* Map output character */
|
/* Map output character */
|
||||||
|
|
@ -814,11 +834,6 @@ int tty_connect(void)
|
||||||
delay(option.output_delay);
|
delay(option.output_delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save previous key */
|
|
||||||
previous_char = input_char;
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if (status == -1)
|
} else if (status == -1)
|
||||||
{
|
{
|
||||||
error_printf("Error: select() failed (%s)", strerror(errno));
|
error_printf("Error: select() failed (%s)", strerror(errno));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue