summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/vty/vty.h9
-rw-r--r--src/vty/command.c54
-rw-r--r--tests/vty/vty_test.c16
3 files changed, 31 insertions, 48 deletions
diff --git a/include/osmocom/vty/vty.h b/include/osmocom/vty/vty.h
index 03a29248..9acaa7d2 100644
--- a/include/osmocom/vty/vty.h
+++ b/include/osmocom/vty/vty.h
@@ -178,9 +178,14 @@ struct vty_app_info {
const char *copyright;
/*! \ref talloc context */
void *tall_ctx;
- /*! call-back for returning to parent n ode */
+ /*! Call-back for taking actions upon exiting a node.
+ * The return value is ignored, and changes to vty->node and vty->index made in this callback are ignored.
+ * Implicit parent node tracking always sets the correct parent node and vty->index after this callback exits,
+ * so this callback can handle only those nodes that should take specific actions upon node exit, or can be left
+ * NULL entirely. */
int (*go_parent_cb)(struct vty *vty);
- /*! call-back to determine if node is config node */
+ /*! OBSOLETED: Implicit parent node tracking has replaced the use of this callback. This callback is no longer
+ * called, ever, and can be left NULL. */
int (*is_config_node)(struct vty *vty, int node);
/*! Check if the config is consistent before write */
int (*config_is_consistent)(struct vty *vty);
diff --git a/src/vty/command.c b/src/vty/command.c
index 6a9d18af..daee5c5a 100644
--- a/src/vty/command.c
+++ b/src/vty/command.c
@@ -200,18 +200,6 @@ static int cmp_desc(const void *p, const void *q)
return strcmp(a->cmd, b->cmd);
}
-static int is_config_child(struct vty *vty)
-{
- if (vty->node <= CONFIG_NODE)
- return 0;
- else if (vty->node > CONFIG_NODE && vty->node < _LAST_OSMOVTY_NODE)
- return 1;
- else if (host.app_info->is_config_node)
- return host.app_info->is_config_node(vty, vty->node);
- else
- return vty->node > CONFIG_NODE;
-}
-
/*! Sort each node's command element according to command string. */
void sort_node(void)
{
@@ -2187,25 +2175,10 @@ int vty_go_parent(struct vty *vty)
vty_clear_parents(vty);
break;
- case CFG_LOG_NODE:
- case VTY_NODE:
- vty->node = CONFIG_NODE;
- vty_clear_parents(vty);
- break;
-
default:
- if (host.app_info->go_parent_cb) {
+ if (host.app_info->go_parent_cb)
host.app_info->go_parent_cb(vty);
- vty_pop_parent(vty);
- }
- else if (is_config_child(vty)) {
- vty->node = CONFIG_NODE;
- vty_clear_parents(vty);
- }
- else {
- vty->node = VIEW_NODE;
- vty_clear_parents(vty);
- }
+ vty_pop_parent(vty);
break;
}
@@ -2365,9 +2338,30 @@ cmd_execute_command_real(vector vline, struct vty *vty,
if (matched_element->daemon)
rc = CMD_SUCCESS_DAEMON;
- else /* Execute matched command. */
+ else {
+ /* Execute matched command. */
+ struct vty_parent_node this_node = {
+ .node = vty->node,
+ .priv = vty->priv,
+ .indent = vty->indent,
+ };
+ struct vty_parent_node *parent = vty_parent(vty);
rc = (*matched_element->func) (matched_element, vty, argc, argv);
+ /* If we have stepped down into a child node, push a parent frame.
+ * The causality is such: we don't expect every single node entry implementation to push
+ * a parent node entry onto vty->parent_nodes. Instead we expect vty_go_parent() to *pop*
+ * a parent node. Hence if the node changed without the parent node changing, we must
+ * have stepped into a child node. */
+ if (vty->node != this_node.node && parent == vty_parent(vty)
+ && vty->node > CONFIG_NODE) {
+ /* Push the parent node. */
+ parent = talloc_zero(vty, struct vty_parent_node);
+ *parent = this_node;
+ llist_add(&parent->entry, &vty->parent_nodes);
+ }
+ }
+
rc_free_deopt_ctx:
/* Now after we called the command func, we can free temporary strings */
talloc_free(cmd_deopt_ctx);
diff --git a/tests/vty/vty_test.c b/tests/vty/vty_test.c
index 1139638d..9627b6d2 100644
--- a/tests/vty/vty_test.c
+++ b/tests/vty/vty_test.c
@@ -482,27 +482,11 @@ void test_is_cmd_ambiguous()
destroy_test_vty(&test, vty);
}
-static int go_parent_cb(struct vty *vty)
-{
- /*
- * - For the interactive VTY tests above, it is expected to bounce back to
- * the CONFIG_NODE. Hence do so in go_parent_cb().
- * - In the config file parsing tests, setting vty->node in go_parent_cb() has no
- * effect, because we will subsequently pop a parent node from the parent stack
- * and override to go to the node that was recorded as the actual parent.
- */
- vty->node = CONFIG_NODE;
- vty->index = NULL;
- return 0;
-}
-
int main(int argc, char **argv)
{
struct vty_app_info vty_info = {
.name = "VtyTest",
.version = 0,
- .go_parent_cb = go_parent_cb,
- .is_config_node = NULL,
};
const struct log_info_cat default_categories[] = {};