mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add option '--exec <command>' for running shell command
Runs shell command with I/O redirected to device.
This commit is contained in:
parent
545d473220
commit
e75e19eb00
9 changed files with 89 additions and 10 deletions
10
TODO
10
TODO
|
|
@ -19,16 +19,6 @@
|
||||||
key navigation left/right and insert/overwrite support. Also history browsing
|
key navigation left/right and insert/overwrite support. Also history browsing
|
||||||
pressing up/down.
|
pressing up/down.
|
||||||
|
|
||||||
* Support for running external command
|
|
||||||
|
|
||||||
Add key command e.g. 'ctrl-t r' which prompts user to run external command.
|
|
||||||
The command will be run in a process which stdin/stdout is redirected to the
|
|
||||||
serial port.
|
|
||||||
|
|
||||||
This is the first step towards maybe also adding automatic support for
|
|
||||||
x/y/zmodem data transfer protocols by calling external programs such as
|
|
||||||
rb/sb, rx/sx, rz/sz, etc.
|
|
||||||
|
|
||||||
* Allow tio to connect to socket
|
* Allow tio to connect to socket
|
||||||
|
|
||||||
After some more consideration I think it makes sense to support connecting to a
|
After some more consideration I think it makes sense to support connecting to a
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,11 @@ Run script on connect once, always, or never.
|
||||||
|
|
||||||
Default value is "always".
|
Default value is "always".
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BR "\-\-exec \fI<command>
|
||||||
|
|
||||||
|
Execute shell command with I/O redirected to device
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BR \-v ", " \-\-version
|
.BR \-v ", " \-\-version
|
||||||
|
|
||||||
|
|
@ -571,6 +576,9 @@ Run script from string
|
||||||
Run script from file
|
Run script from file
|
||||||
.IP "\fBscript-run"
|
.IP "\fBscript-run"
|
||||||
Run script on connect
|
Run script on connect
|
||||||
|
.IP "\fBexec"
|
||||||
|
Execute shell command with I/O redirected to device
|
||||||
|
|
||||||
|
|
||||||
.SH "CONFIGURATION FILE EXAMPLES"
|
.SH "CONFIGURATION FILE EXAMPLES"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ _tio()
|
||||||
--script \
|
--script \
|
||||||
--script-file \
|
--script-file \
|
||||||
--script-run \
|
--script-run \
|
||||||
|
--exec \
|
||||||
-v --version \
|
-v --version \
|
||||||
-h --help"
|
-h --help"
|
||||||
|
|
||||||
|
|
@ -179,6 +180,10 @@ _tio()
|
||||||
COMPREPLY=( $(compgen -W "once always never" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "once always never" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
--exec)
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,7 @@ static void config_parse_keys(GKeyFile *key_file, char *group)
|
||||||
g_free((void *)string);
|
g_free((void *)string);
|
||||||
string = NULL;
|
string = NULL;
|
||||||
}
|
}
|
||||||
|
config_get_string(key_file, group, "exec", &option.exec, NULL);
|
||||||
config_get_string(key_file, group, "prefix-ctrl-key", &string, NULL);
|
config_get_string(key_file, group, "prefix-ctrl-key", &string, NULL);
|
||||||
if (string != NULL)
|
if (string != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
59
src/misc.c
59
src/misc.c
|
|
@ -33,6 +33,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
|
@ -199,3 +200,61 @@ bool match_patterns(const char *string, const char *patterns)
|
||||||
free(patterns_copy);
|
free(patterns_copy);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function that forks subprocess, redirects its stdin and stdout to the
|
||||||
|
// specified filedescriptor, and runs command.
|
||||||
|
int execute_shell_command(int fd, const char *command)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
// Fork a child process
|
||||||
|
pid = fork();
|
||||||
|
if (pid == -1)
|
||||||
|
{
|
||||||
|
// Error occurred
|
||||||
|
tio_error_print("fork() failed (%s)", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else if (pid == 0)
|
||||||
|
{
|
||||||
|
// Child process
|
||||||
|
|
||||||
|
tio_printf("Executing shell command '%s'", command);
|
||||||
|
|
||||||
|
// Redirect stdout and stderr to the file descriptor
|
||||||
|
if (dup2(fd, STDOUT_FILENO) == -1 || dup2(fd, STDERR_FILENO) == -1)
|
||||||
|
{
|
||||||
|
tio_error_print("dup2() failed (%s)", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the shell command
|
||||||
|
execl("/bin/sh", "sh", "-c", command, (char *)NULL);
|
||||||
|
|
||||||
|
// If execlp() returns, it means an error occurred
|
||||||
|
perror("execlp");
|
||||||
|
tio_error_print("execlp() failed (%s)", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Parent process
|
||||||
|
|
||||||
|
// Wait for the child process to finish
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
|
||||||
|
if (WIFEXITED(status))
|
||||||
|
{
|
||||||
|
tio_printf("Command exited with status %d", WEXITSTATUS(status));
|
||||||
|
return WEXITSTATUS(status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tio_error_printf("Child process exited abnormally\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,3 +34,4 @@ char *base62_encode(unsigned long num);
|
||||||
int read_poll(int fd, void *data, size_t len, int timeout);
|
int read_poll(int fd, void *data, size_t len, int timeout);
|
||||||
double get_current_time(void);
|
double get_current_time(void);
|
||||||
bool match_patterns(const char *string, const char *patterns);
|
bool match_patterns(const char *string, const char *patterns);
|
||||||
|
int execute_shell_command(int fd, const char *command);
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ enum opt_t
|
||||||
OPT_EXCLUDE_DEVICES,
|
OPT_EXCLUDE_DEVICES,
|
||||||
OPT_EXCLUDE_DRIVERS,
|
OPT_EXCLUDE_DRIVERS,
|
||||||
OPT_EXCLUDE_TIDS,
|
OPT_EXCLUDE_TIDS,
|
||||||
|
OPT_EXEC,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default options */
|
/* Default options */
|
||||||
|
|
@ -121,6 +122,7 @@ struct option_t option =
|
||||||
.exclude_tids = NULL,
|
.exclude_tids = NULL,
|
||||||
.hex_n_value = 0,
|
.hex_n_value = 0,
|
||||||
.vt100 = false,
|
.vt100 = false,
|
||||||
|
.exec = NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
void option_print_help(char *argv[])
|
void option_print_help(char *argv[])
|
||||||
|
|
@ -167,6 +169,7 @@ void option_print_help(char *argv[])
|
||||||
printf(" --script <string> Run script from string\n");
|
printf(" --script <string> Run script from string\n");
|
||||||
printf(" --script-file <filename> Run script from file\n");
|
printf(" --script-file <filename> Run script from file\n");
|
||||||
printf(" --script-run once|always|never Run script on connect (default: always)\n");
|
printf(" --script-run once|always|never Run script on connect (default: always)\n");
|
||||||
|
printf(" --exec <command> Execute shell command with I/O redirected to device\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");
|
||||||
|
|
@ -815,6 +818,7 @@ void options_parse(int argc, char *argv[])
|
||||||
{"script", required_argument, 0, OPT_SCRIPT },
|
{"script", required_argument, 0, OPT_SCRIPT },
|
||||||
{"script-file", required_argument, 0, OPT_SCRIPT_FILE },
|
{"script-file", required_argument, 0, OPT_SCRIPT_FILE },
|
||||||
{"script-run", required_argument, 0, OPT_SCRIPT_RUN },
|
{"script-run", required_argument, 0, OPT_SCRIPT_RUN },
|
||||||
|
{"exec", required_argument, 0, OPT_EXEC },
|
||||||
{"version", no_argument, 0, 'v' },
|
{"version", no_argument, 0, 'v' },
|
||||||
{"help", no_argument, 0, 'h' },
|
{"help", no_argument, 0, 'h' },
|
||||||
{"complete-profiles", no_argument, 0, OPT_COMPLETE_PROFILES },
|
{"complete-profiles", no_argument, 0, OPT_COMPLETE_PROFILES },
|
||||||
|
|
@ -985,6 +989,10 @@ void options_parse(int argc, char *argv[])
|
||||||
option_parse_script_run(optarg, &option.script_run);
|
option_parse_script_run(optarg, &option.script_run);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OPT_EXEC:
|
||||||
|
option.exec = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("tio v%s\n", VERSION);
|
printf("tio v%s\n", VERSION);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ struct option_t
|
||||||
char *exclude_tids;
|
char *exclude_tids;
|
||||||
int hex_n_value;
|
int hex_n_value;
|
||||||
bool vt100;
|
bool vt100;
|
||||||
|
char *exec;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct option_t option;
|
extern struct option_t option;
|
||||||
|
|
|
||||||
|
|
@ -2277,6 +2277,12 @@ int tty_connect(void)
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option.exec != NULL)
|
||||||
|
{
|
||||||
|
int status = execute_shell_command(device_fd, option.exec);
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
|
|
||||||
/* Input loop */
|
/* Input loop */
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue