From 791ded4a62b86d3e05d28e70864ee2723d91bc69 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Sun, 9 Sep 2018 00:03:19 +0200 Subject: [PATCH] *: add ->node_exit to struct cmd_node Rather than doing a f*gly hack for the RPKI code, let's do an on-exit hook in cmd_node. Also allows replacing some special-casing in the vty code. Signed-off-by: David Lamparter --- bgpd/bgp_rpki.c | 53 ++++--------------------------------------------- lib/command.c | 36 +++++++++++++++++---------------- lib/command.h | 5 +++++ lib/vty.c | 19 +++++++++++------- lib/vty.h | 1 + 5 files changed, 41 insertions(+), 73 deletions(-) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 11ef8563c4..1ba07e95e6 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -104,7 +104,7 @@ static struct rtr_mgr_group *get_connected_group(void); static void print_prefix_table(struct vty *vty); static void install_cli_commands(void); static int config_write(struct vty *vty); -static void overwrite_exit_commands(void); +static int config_on_exit(struct vty *vty); static void free_cache(struct cache *cache); static struct rtr_mgr_group *get_groups(void); #if defined(FOUND_SSH) @@ -149,6 +149,7 @@ static struct cmd_node rpki_node = { .parent_node = CONFIG_NODE, .prompt = "%s(config-rpki)# ", .config_write = config_write, + .node_exit = config_on_exit, }; static const struct route_map_rule_cmd route_match_rpki_cmd = { "rpki", route_match, route_match_compile, route_match_free}; @@ -1400,35 +1401,10 @@ DEFUN (show_rpki_cache_connection, return CMD_SUCCESS; } -DEFUN_NOSH (rpki_exit, - rpki_exit_cmd, - "exit", - "Exit rpki configuration and restart rpki session\n") +static int config_on_exit(struct vty *vty) { reset(false); - - vty->node = CONFIG_NODE; - return CMD_SUCCESS; -} - -DEFUN_NOSH (rpki_quit, - rpki_quit_cmd, - "quit", - "Exit rpki configuration mode\n") -{ - return rpki_exit(self, vty, argc, argv); -} - -DEFUN_NOSH (rpki_end, - rpki_end_cmd, - "end", - "End rpki configuration, restart rpki session and change to enable mode.\n") -{ - int ret = reset(false); - - vty_config_exit(vty); - vty->node = ENABLE_NODE; - return ret == SUCCESS ? CMD_SUCCESS : CMD_WARNING; + return 1; } DEFUN (rpki_reset, @@ -1522,32 +1498,11 @@ DEFUN (no_match_rpki, return CMD_SUCCESS; } -static void overwrite_exit_commands(void) -{ - unsigned int i; - vector cmd_vector = rpki_node.cmd_vector; - - for (i = 0; i < cmd_vector->active; ++i) { - struct cmd_element *cmd = vector_lookup(cmd_vector, i); - - if (strcmp(cmd->string, "exit") == 0 - || strcmp(cmd->string, "quit") == 0 - || strcmp(cmd->string, "end") == 0) { - uninstall_element(RPKI_NODE, cmd); - } - } - - install_element(RPKI_NODE, &rpki_exit_cmd); - install_element(RPKI_NODE, &rpki_quit_cmd); - install_element(RPKI_NODE, &rpki_end_cmd); -} - static void install_cli_commands(void) { // TODO: make config write work install_node(&rpki_node); install_default(RPKI_NODE); - overwrite_exit_commands(); install_element(CONFIG_NODE, &rpki_cmd); install_element(ENABLE_NODE, &rpki_cmd); diff --git a/lib/command.c b/lib/command.c index 8ec93c1b33..d51922dfa1 100644 --- a/lib/command.c +++ b/lib/command.c @@ -99,6 +99,8 @@ const char *cmd_domainname_get(void) return host.domainname; } +static int root_on_exit(struct vty *vty); + /* Standard command node structures. */ static struct cmd_node auth_node = { .name = "auth", @@ -110,6 +112,7 @@ static struct cmd_node view_node = { .name = "view", .node = VIEW_NODE, .prompt = "%s> ", + .node_exit = root_on_exit, }; static struct cmd_node auth_enable_node = { @@ -122,6 +125,7 @@ static struct cmd_node enable_node = { .name = "enable", .node = ENABLE_NODE, .prompt = "%s# ", + .node_exit = root_on_exit, }; static int config_write_host(struct vty *vty); @@ -131,6 +135,7 @@ static struct cmd_node config_node = { .parent_node = ENABLE_NODE, .prompt = "%s(config)# ", .config_write = config_write_host, + .node_exit = vty_config_node_exit, }; static const struct facility_map { @@ -1382,28 +1387,25 @@ DEFUN (config_exit, return CMD_SUCCESS; } +static int root_on_exit(struct vty *vty) +{ + if (vty_shell(vty)) + exit(0); + else + vty->status = VTY_CLOSE; + return 0; +} + void cmd_exit(struct vty *vty) { struct cmd_node *cnode = vector_lookup(cmdvec, vty->node); - switch (vty->node) { - case VIEW_NODE: - case ENABLE_NODE: - if (vty_shell(vty)) - exit(0); - else - vty->status = VTY_CLOSE; - break; - case CONFIG_NODE: - vty->node = ENABLE_NODE; - vty_config_exit(vty); - break; - default: - if (cnode->parent_node) - vty->node = cnode->parent_node; - break; + if (cnode->node_exit) { + if (!cnode->node_exit(vty)) + return; } - + if (cnode->parent_node) + vty->node = cnode->parent_node; if (vty->xpath_index > 0) vty->xpath_index--; } diff --git a/lib/command.h b/lib/command.h index 5629eb3679..e7c9ff4c52 100644 --- a/lib/command.h +++ b/lib/command.h @@ -182,6 +182,11 @@ struct cmd_node { /* Node's configuration write function */ int (*config_write)(struct vty *); + /* called when leaving the node on a VTY session. + * return 1 if normal exit processing should happen, 0 to suppress + */ + int (*node_exit)(struct vty *); + /* Node's command graph */ struct graph *cmdgraph; diff --git a/lib/vty.c b/lib/vty.c index 683c39f893..86d0a36aa0 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -2199,6 +2199,9 @@ void vty_close(struct vty *vty) int i; bool was_stdio = false; + /* Drop out of configure / transaction if needed. */ + vty_config_exit(vty); + /* Cancel threads.*/ THREAD_OFF(vty->t_read); THREAD_OFF(vty->t_write); @@ -2242,9 +2245,6 @@ void vty_close(struct vty *vty) list_delete(&vty->error); } - /* Check configure. */ - vty_config_exit(vty); - /* OK free vty. */ XFREE(MTYPE_VTY, vty); @@ -2614,14 +2614,18 @@ void vty_config_exit(struct vty *vty) cnode = vector_lookup(cmdvec, node); node = cnode->parent_node; } - if (node != CONFIG_NODE) { - vty_out(vty, - "WARNING: vty_config_exit() from outside CONFIG_NODE!\n"); + if (node != CONFIG_NODE) + /* called outside config, e.g. vty_close() in ENABLE_NODE */ return; - } while (vty->node != ENABLE_NODE) + /* will call vty_config_node_exit() below */ cmd_exit(vty); +} + +int vty_config_node_exit(struct vty *vty) +{ + vty->xpath_index = 0; /* Check if there's a pending confirmed commit. */ if (vty->t_confirmed_commit_timeout) { @@ -2644,6 +2648,7 @@ void vty_config_exit(struct vty *vty) } vty->config = false; + return 1; } /* Master of the threads. */ diff --git a/lib/vty.h b/lib/vty.h index f90a35a260..694aac3944 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -323,6 +323,7 @@ extern void vty_log(const char *level, const char *proto, const char *msg, extern int vty_config_enter(struct vty *vty, bool private_config, bool exclusive); extern void vty_config_exit(struct vty *); +extern int vty_config_node_exit(struct vty *); extern int vty_shell(struct vty *); extern int vty_shell_serv(struct vty *); extern void vty_hello(struct vty *);