This commit is contained in:
Mark Stapp 2025-04-29 16:22:43 +00:00 committed by GitHub
commit 471f51374e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 125 additions and 3 deletions

View file

@ -83,6 +83,18 @@ and the :clicmd:`terminal paginate` command:
(likely ``more`` or ``/usr/bin/pager``) will be used.
Idle Timeout
============
.. clicmd:: exec-timeout TIMEOUT
Enable an idle timeout for the vtysh session, in seconds. When
configured, the vtysh process will exit if the session is
idle. The timeout can be configured via ``vtysh.conf``, via a
``-T, --exec-timeout`` command-line option, or in the configure
mode. A timeout of zero is equivalent to "no timeout".
Permissions and setup requirements
==================================

View file

@ -4253,6 +4253,21 @@ DEFUN (vtysh_show_daemons,
return CMD_SUCCESS;
}
DEFPY (vtysh_exec_timeout,
vtysh_exec_timeout_cmd,
"[no$nono] exec-timeout ![(0-1000000)$tsecs]",
NO_STR
"Set the VTYSH EXEC timeout\n"
"Timeout in seconds\n")
{
if (nono)
tsecs = 0;
vtysh_exec_timeout_config(tsecs);
return CMD_SUCCESS;
}
struct visual_prio {
/* 4 characters for nice alignment */
const char *label;
@ -5669,4 +5684,5 @@ void vtysh_init_vty(void)
install_element(CONFIG_NODE, &no_vtysh_password_cmd);
install_element(CONFIG_NODE, &vtysh_enable_password_cmd);
install_element(CONFIG_NODE, &no_vtysh_enable_password_cmd);
install_element(CONFIG_NODE, &vtysh_exec_timeout_cmd);
}

View file

@ -149,6 +149,11 @@ void vtysh_config_init(void);
void suid_on(void);
void suid_off(void);
/* Handle exec-timeout config changes */
#define VTYSH_EXEC_TIMEOUT_MAX 1000 * 1000
void vtysh_exec_timeout_config(uint32_t tsecs);
uint32_t vtysh_get_exec_timeout(void);
/* Child process execution flag. */
extern int execute_flag;

View file

@ -767,6 +767,7 @@ void vtysh_config_write(void)
{
const char *name;
char line[512];
uint32_t ival;
name = cmd_hostname_get();
if (name && name[0] != '\0') {
@ -787,6 +788,12 @@ void vtysh_config_write(void)
vtysh_config_parse_line(NULL,
"service integrated-vtysh-config");
ival = vtysh_get_exec_timeout();
if (ival > 0) {
snprintf(line, sizeof(line), "exec-timeout %u", ival);
vtysh_config_parse_line(NULL, line);
}
user_config_write();
}

View file

@ -71,11 +71,72 @@ struct event_loop *master;
/* Command logging */
FILE *logfile;
static struct event *ev_exec_timeout;
uint32_t vtysh_exec_timeout;
static void handle_exec_timeout(struct event *event);
/*
* Disable/disarm the exec timeout
*/
static void disable_exec_timeout(void)
{
event_cancel(&ev_exec_timeout);
}
/*
* Enable/arm the exec timeout, if configured
*/
static void enable_exec_timeout(void)
{
/* This may be called quite early; ensure the event-loop is running */
if (master != NULL && vtysh_exec_timeout > 0)
event_add_timer(master, handle_exec_timeout, NULL,
vtysh_exec_timeout, &ev_exec_timeout);
}
/*
* Handler for exec-timeout config changes; takes timeout in seconds, and zero
* means "no timeout"
*/
void vtysh_exec_timeout_config(uint32_t tsecs)
{
vtysh_exec_timeout = tsecs;
disable_exec_timeout();
if (vtysh_exec_timeout > 0)
enable_exec_timeout();
}
/*
* Accessor for configured exec timeout
*/
uint32_t vtysh_get_exec_timeout(void)
{
return vtysh_exec_timeout;
}
/*
* Handler for exec timeout timer
*/
static void handle_exec_timeout(struct event *event)
{
rl_callback_handler_remove();
/* Execute "end" command. */
vtysh_execute("end");
vtysh_loop_exited = true;
printf("Vtysh timed-out, exiting\n");
}
static void vtysh_rl_callback(char *line_read)
{
HIST_ENTRY *last;
rl_callback_handler_remove();
disable_exec_timeout();
if (!line_read) {
vtysh_loop_exited = true;
@ -96,8 +157,10 @@ static void vtysh_rl_callback(char *line_read)
vtysh_execute(line_read);
if (!vtysh_loop_exited)
if (!vtysh_loop_exited) {
rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
enable_exec_timeout();
}
free(line_read);
}
@ -182,6 +245,7 @@ static FRR_NORETURN void usage(int status)
"-H, --histfile Override history file\n"
"-t, --timestamp Print a timestamp before going to shell or reading the configuration\n"
" --no-fork Don't fork clients to handle daemons (slower for large configs)\n"
"-T, --exec-timeout Set an idle timeout for this vtysh session\n"
"-h, --help Display this help and exit\n\n"
"Note that multiple commands may be executed from the command\n"
"line by passing multiple -c args, or by embedding linefeed\n"
@ -216,6 +280,7 @@ struct option longopts[] = {
{"user", no_argument, NULL, 'u'},
{"timestamp", no_argument, NULL, 't'},
{"no-fork", no_argument, NULL, OPTION_NOFORK},
{"exec-timeout", required_argument, NULL, 'T'},
{0}};
bool vtysh_loop_exited;
@ -226,9 +291,13 @@ static void vtysh_rl_read(struct event *thread)
{
bool *suppress_warnings = EVENT_ARG(thread);
disable_exec_timeout();
event_add_read(master, vtysh_rl_read, suppress_warnings, STDIN_FILENO,
&vtysh_rl_read_thread);
rl_callback_read_char();
enable_exec_timeout();
}
/* Read a string, and return a pointer to it. Returns NULL on EOF. */
@ -243,6 +312,8 @@ static void vtysh_rl_run(void)
event_add_read(master, vtysh_rl_read, &suppress_warnings, STDIN_FILENO,
&vtysh_rl_read_thread);
enable_exec_timeout();
while (!vtysh_loop_exited && event_fetch(master, &thread))
event_call(&thread);
@ -351,6 +422,7 @@ int main(int argc, char **argv, char **env)
const char *histfile = NULL;
const char *histfile_env = getenv("VTYSH_HISTFILE");
const char *logpath = getenv("VTYSH_LOG");
int exec_timeout = 0;
/* SUID: drop down to calling user & go back up when needed */
elevuid = geteuid();
@ -370,8 +442,7 @@ int main(int argc, char **argv, char **env)
/* Option handling. */
while (1) {
opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:ut", longopts,
0);
opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:utT:", longopts, 0);
if (opt == EOF)
break;
@ -447,6 +518,13 @@ int main(int argc, char **argv, char **env)
case 'H':
histfile = optarg;
break;
case 'T':
exec_timeout = atoi(optarg);
if (exec_timeout < 0 || exec_timeout > VTYSH_EXEC_TIMEOUT_MAX) {
fprintf(stderr, "Exec-timeout value invalid\n");
exit(1);
}
break;
default:
usage(1);
break;
@ -515,6 +593,10 @@ int main(int argc, char **argv, char **env)
return (vtysh_mark_file(inputfile));
}
/* Allow command-line control of timeout */
if (exec_timeout > 0)
vtysh_exec_timeout_config(exec_timeout);
/* Start execution only if not in dry-run mode */
if (dryrun && !cmd) {
if (inputfile) {