2014-06-16 08:13:40 +00:00
|
|
|
#pragma once
|
2010-05-19 17:02:52 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
2019-04-10 00:41:53 +00:00
|
|
|
#include <stdbool.h>
|
2021-09-05 21:08:59 +00:00
|
|
|
#include <time.h>
|
2010-05-19 17:02:52 +00:00
|
|
|
|
VTY: implicit node exit by de-indenting, not parent lookup
Note: This will break users' config files if they do not use consistent
indenting. (see below for a definition of "consistent".)
When reading VTY commands from a file, use indenting as means to implicitly
exit child nodes. Do not look for commands in the parent node implicitly.
The VTY so far implies 'exit' commands if a VTY line cannot be parsed on the
current node, but succeeds on the parent node. That is the mechanism by which
our VTY config files do not need 'exit' at the end of each child node.
We've hit problems with this in the following scenarios, which will show
improved user experience after this patch:
*) When both a parent and its child node have commands with identical names:
cs7 instace 0
point-code 1.2.3
sccp-address osmo-msc
point-code 0.0.1
If I put the parent's command below the child, it is still interpreted in the
context of the child node:
cs7 instace 0
sccp-address osmo-msc
point-code 0.0.1
point-code 1.2.3
Though the indenting lets me assume I am setting the cs7 instance's global PC
to 1.2.3, I'm actually overwriting osmo-msc's PC with 1.2.3 and discarding the
0.0.1.
*) When a software change moves a VTY command from a child to a parent. Say
'timezone' moved from 'bts' to 'network' level:
network
timezone 1 2
Say a user still has an old config file with 'timezone' on the child level:
network
bts 0
timezone 1 2
trx 0
The user would expect an error message that 'timezone' is invalid on the 'bts'
level. Instead, the VTY finds the parent node's 'timezone', steps out of 'bts'
to the 'network' level, and instead says that the 'trx' command does not exist.
Format:
Consistent means that two adjacent indenting lines have the exact
same indenting characters for the common length:
Weird mix if you ask me, but correct and consistent:
ROOT
<space>PARENT
<space><tab><space>CHILD
<space><tab><space><tab><tab>GRANDCHILD
<space><tab><space><tab><tab>GRANDCHILD2
<space>SIBLING
Inconsistent:
ROOT
<space>PARENT
<tab><space>CHILD
<space><space><tab>GRANDCHILD
<space><tab><tab>GRANDCHILD2
<tab>SIBLING
Also, when going back to a parent level, the exact same indenting must be used
as before in that node:
Incorrect:
ROOT
<tab>PARENT
<tab><tab><tab>CHILD
<tab><tab>SIBLING
As not really intended side effect, it is also permitted to indent the entire
file starting from the root level. We could guard against it but there's no
harm:
Correct and consistent:
<tab>ROOT
<tab><tab>PARENT
<tab><tab><tab><tab>CHILD
<tab><tab>SIBLING
Implementation:
Track parent nodes state: whenever a command enters a child node, push a parent
node onto an llist to remember the exact indentation characters used for that
level.
As soon as the first line on a child node is parsed, remember this new
indentation (which must have a longer strlen() than its parent level) to apply
to all remaining child siblings and grandchildren.
If the amount of spaces that indent a following VTY command are less than this
expected indentation, call vty_go_parent() until it matches up.
At any level, if the common length of indentation characters mismatch, abort
parsing in error.
Transitions to child node are spread across VTY implementations and are hard to
change. But transitions to the parent node are all handled by vty_go_parent().
By popping a parent from the list of parents in vty_go_parent(), we can also
detect that a command has changed the node without changing the parent, hence
it must have stepped into a child node, and we can push a parent frame.
The behavior on the interactive telnet VTY remains unchanged.
Change-Id: I24cbb3f6de111f2d31110c3c484c066f1153aac9
2017-09-07 01:08:06 +00:00
|
|
|
#include <osmocom/core/linuxlist.h>
|
2019-11-24 18:52:44 +00:00
|
|
|
#include <osmocom/core/defs.h>
|
VTY: implicit node exit by de-indenting, not parent lookup
Note: This will break users' config files if they do not use consistent
indenting. (see below for a definition of "consistent".)
When reading VTY commands from a file, use indenting as means to implicitly
exit child nodes. Do not look for commands in the parent node implicitly.
The VTY so far implies 'exit' commands if a VTY line cannot be parsed on the
current node, but succeeds on the parent node. That is the mechanism by which
our VTY config files do not need 'exit' at the end of each child node.
We've hit problems with this in the following scenarios, which will show
improved user experience after this patch:
*) When both a parent and its child node have commands with identical names:
cs7 instace 0
point-code 1.2.3
sccp-address osmo-msc
point-code 0.0.1
If I put the parent's command below the child, it is still interpreted in the
context of the child node:
cs7 instace 0
sccp-address osmo-msc
point-code 0.0.1
point-code 1.2.3
Though the indenting lets me assume I am setting the cs7 instance's global PC
to 1.2.3, I'm actually overwriting osmo-msc's PC with 1.2.3 and discarding the
0.0.1.
*) When a software change moves a VTY command from a child to a parent. Say
'timezone' moved from 'bts' to 'network' level:
network
timezone 1 2
Say a user still has an old config file with 'timezone' on the child level:
network
bts 0
timezone 1 2
trx 0
The user would expect an error message that 'timezone' is invalid on the 'bts'
level. Instead, the VTY finds the parent node's 'timezone', steps out of 'bts'
to the 'network' level, and instead says that the 'trx' command does not exist.
Format:
Consistent means that two adjacent indenting lines have the exact
same indenting characters for the common length:
Weird mix if you ask me, but correct and consistent:
ROOT
<space>PARENT
<space><tab><space>CHILD
<space><tab><space><tab><tab>GRANDCHILD
<space><tab><space><tab><tab>GRANDCHILD2
<space>SIBLING
Inconsistent:
ROOT
<space>PARENT
<tab><space>CHILD
<space><space><tab>GRANDCHILD
<space><tab><tab>GRANDCHILD2
<tab>SIBLING
Also, when going back to a parent level, the exact same indenting must be used
as before in that node:
Incorrect:
ROOT
<tab>PARENT
<tab><tab><tab>CHILD
<tab><tab>SIBLING
As not really intended side effect, it is also permitted to indent the entire
file starting from the root level. We could guard against it but there's no
harm:
Correct and consistent:
<tab>ROOT
<tab><tab>PARENT
<tab><tab><tab><tab>CHILD
<tab><tab>SIBLING
Implementation:
Track parent nodes state: whenever a command enters a child node, push a parent
node onto an llist to remember the exact indentation characters used for that
level.
As soon as the first line on a child node is parsed, remember this new
indentation (which must have a longer strlen() than its parent level) to apply
to all remaining child siblings and grandchildren.
If the amount of spaces that indent a following VTY command are less than this
expected indentation, call vty_go_parent() until it matches up.
At any level, if the common length of indentation characters mismatch, abort
parsing in error.
Transitions to child node are spread across VTY implementations and are hard to
change. But transitions to the parent node are all handled by vty_go_parent().
By popping a parent from the list of parents in vty_go_parent(), we can also
detect that a command has changed the node without changing the parent, hence
it must have stepped into a child node, and we can push a parent frame.
The behavior on the interactive telnet VTY remains unchanged.
Change-Id: I24cbb3f6de111f2d31110c3c484c066f1153aac9
2017-09-07 01:08:06 +00:00
|
|
|
|
2011-08-17 15:13:48 +00:00
|
|
|
/*! \defgroup vty VTY (Virtual TTY) interface
|
|
|
|
* @{
|
2017-06-20 02:35:06 +00:00
|
|
|
* \file vty.h */
|
2011-08-17 15:13:48 +00:00
|
|
|
|
2010-05-19 17:02:52 +00:00
|
|
|
/* GCC have printf type attribute check. */
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#define VTY_PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
|
|
|
|
#else
|
|
|
|
#define VTY_PRINTF_ATTRIBUTE(a,b)
|
|
|
|
#endif /* __GNUC__ */
|
|
|
|
|
|
|
|
/* Does the I/O error indicate that the operation should be retried later? */
|
|
|
|
#define ERRNO_IO_RETRY(EN) \
|
|
|
|
(((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
|
|
|
|
|
|
|
|
/* Vty read buffer size. */
|
|
|
|
#define VTY_READ_BUFSIZ 512
|
|
|
|
|
|
|
|
#define VTY_BUFSIZ 512
|
|
|
|
#define VTY_MAXHIST 20
|
|
|
|
|
2020-10-06 10:41:22 +00:00
|
|
|
/* Number of application / library specific VTY attributes */
|
|
|
|
#define VTY_CMD_USR_ATTR_NUM 32
|
2020-10-07 06:44:31 +00:00
|
|
|
/* Flag characters reserved for global VTY attributes */
|
|
|
|
#define VTY_CMD_ATTR_FLAGS_RESERVED \
|
2020-10-20 22:07:34 +00:00
|
|
|
{ '.', '!', '@', '^' }
|
2020-10-06 10:41:22 +00:00
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! VTY events */
|
2010-05-19 17:02:52 +00:00
|
|
|
enum event {
|
|
|
|
VTY_SERV,
|
|
|
|
VTY_READ,
|
|
|
|
VTY_WRITE,
|
|
|
|
VTY_CLOSED,
|
|
|
|
VTY_TIMEOUT_RESET,
|
|
|
|
#ifdef VTYSH
|
|
|
|
VTYSH_SERV,
|
|
|
|
VTYSH_READ,
|
|
|
|
VTYSH_WRITE
|
|
|
|
#endif /* VTYSH */
|
|
|
|
};
|
|
|
|
|
2012-07-12 07:22:56 +00:00
|
|
|
enum vty_type {
|
|
|
|
VTY_TERM,
|
|
|
|
VTY_FILE,
|
|
|
|
VTY_SHELL,
|
|
|
|
VTY_SHELL_SERV
|
|
|
|
};
|
|
|
|
|
2011-08-17 15:13:48 +00:00
|
|
|
/*! Internal representation of a single VTY */
|
2010-05-19 17:02:52 +00:00
|
|
|
struct vty {
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! underlying file (if any) */
|
2010-05-19 17:02:52 +00:00
|
|
|
FILE *file;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! private data, specified by creator */
|
2010-05-19 17:02:52 +00:00
|
|
|
void *priv;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! File descripter of this vty. */
|
2010-05-19 17:02:52 +00:00
|
|
|
int fd;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Is this vty connect to file or not */
|
2012-07-12 07:22:56 +00:00
|
|
|
enum vty_type type;
|
2010-05-19 17:02:52 +00:00
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Node status of this vty */
|
2010-05-19 17:02:52 +00:00
|
|
|
int node;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Failure count */
|
2010-05-19 17:02:52 +00:00
|
|
|
int fail;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Output buffer. */
|
2010-05-19 17:02:52 +00:00
|
|
|
struct buffer *obuf;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Command input buffer */
|
2010-05-19 17:02:52 +00:00
|
|
|
char *buf;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Command cursor point */
|
2010-05-19 17:02:52 +00:00
|
|
|
int cp;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Command length */
|
2010-05-19 17:02:52 +00:00
|
|
|
int length;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Command max length. */
|
2010-05-19 17:02:52 +00:00
|
|
|
int max;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Histry of command */
|
2010-05-19 17:02:52 +00:00
|
|
|
char *hist[VTY_MAXHIST];
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! History lookup current point */
|
2010-05-19 17:02:52 +00:00
|
|
|
int hp;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! History insert end point */
|
2010-05-19 17:02:52 +00:00
|
|
|
int hindex;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! For current referencing point of interface, route-map,
|
2010-05-19 17:02:52 +00:00
|
|
|
access-list etc... */
|
|
|
|
void *index;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! For multiple level index treatment such as key chain and key. */
|
2010-05-19 17:02:52 +00:00
|
|
|
void *index_sub;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! For escape character. */
|
2010-05-19 17:02:52 +00:00
|
|
|
unsigned char escape;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Current vty status. */
|
2010-05-19 17:02:52 +00:00
|
|
|
enum { VTY_NORMAL, VTY_CLOSE, VTY_MORE, VTY_MORELINE } status;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! IAC handling
|
2011-08-17 15:13:48 +00:00
|
|
|
*
|
|
|
|
* IAC handling: was the last character received the IAC
|
2010-05-19 17:02:52 +00:00
|
|
|
* (interpret-as-command) escape character (and therefore the next
|
|
|
|
* character will be the command code)? Refer to Telnet RFC 854. */
|
|
|
|
unsigned char iac;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! IAC SB (option subnegotiation) handling */
|
2010-05-19 17:02:52 +00:00
|
|
|
unsigned char iac_sb_in_progress;
|
|
|
|
/* At the moment, we care only about the NAWS (window size) negotiation,
|
|
|
|
* and that requires just a 5-character buffer (RFC 1073):
|
|
|
|
* <NAWS char> <16-bit width> <16-bit height> */
|
|
|
|
#define TELNET_NAWS_SB_LEN 5
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! sub-negotiation buffer */
|
2010-05-19 17:02:52 +00:00
|
|
|
unsigned char sb_buf[TELNET_NAWS_SB_LEN];
|
2021-05-18 12:46:29 +00:00
|
|
|
/*! How many subnegotiation characters have we received?
|
2011-08-17 15:13:48 +00:00
|
|
|
*
|
|
|
|
* We just drop those that do not fit in the buffer. */
|
2010-05-19 17:02:52 +00:00
|
|
|
size_t sb_len;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Window width */
|
2010-05-19 17:02:52 +00:00
|
|
|
int width;
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Widnow height */
|
2010-05-19 17:02:52 +00:00
|
|
|
int height;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Configure lines. */
|
2010-05-19 17:02:52 +00:00
|
|
|
int lines;
|
|
|
|
|
|
|
|
int monitor;
|
|
|
|
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! In configure mode. */
|
2010-05-19 17:02:52 +00:00
|
|
|
int config;
|
VTY: implicit node exit by de-indenting, not parent lookup
Note: This will break users' config files if they do not use consistent
indenting. (see below for a definition of "consistent".)
When reading VTY commands from a file, use indenting as means to implicitly
exit child nodes. Do not look for commands in the parent node implicitly.
The VTY so far implies 'exit' commands if a VTY line cannot be parsed on the
current node, but succeeds on the parent node. That is the mechanism by which
our VTY config files do not need 'exit' at the end of each child node.
We've hit problems with this in the following scenarios, which will show
improved user experience after this patch:
*) When both a parent and its child node have commands with identical names:
cs7 instace 0
point-code 1.2.3
sccp-address osmo-msc
point-code 0.0.1
If I put the parent's command below the child, it is still interpreted in the
context of the child node:
cs7 instace 0
sccp-address osmo-msc
point-code 0.0.1
point-code 1.2.3
Though the indenting lets me assume I am setting the cs7 instance's global PC
to 1.2.3, I'm actually overwriting osmo-msc's PC with 1.2.3 and discarding the
0.0.1.
*) When a software change moves a VTY command from a child to a parent. Say
'timezone' moved from 'bts' to 'network' level:
network
timezone 1 2
Say a user still has an old config file with 'timezone' on the child level:
network
bts 0
timezone 1 2
trx 0
The user would expect an error message that 'timezone' is invalid on the 'bts'
level. Instead, the VTY finds the parent node's 'timezone', steps out of 'bts'
to the 'network' level, and instead says that the 'trx' command does not exist.
Format:
Consistent means that two adjacent indenting lines have the exact
same indenting characters for the common length:
Weird mix if you ask me, but correct and consistent:
ROOT
<space>PARENT
<space><tab><space>CHILD
<space><tab><space><tab><tab>GRANDCHILD
<space><tab><space><tab><tab>GRANDCHILD2
<space>SIBLING
Inconsistent:
ROOT
<space>PARENT
<tab><space>CHILD
<space><space><tab>GRANDCHILD
<space><tab><tab>GRANDCHILD2
<tab>SIBLING
Also, when going back to a parent level, the exact same indenting must be used
as before in that node:
Incorrect:
ROOT
<tab>PARENT
<tab><tab><tab>CHILD
<tab><tab>SIBLING
As not really intended side effect, it is also permitted to indent the entire
file starting from the root level. We could guard against it but there's no
harm:
Correct and consistent:
<tab>ROOT
<tab><tab>PARENT
<tab><tab><tab><tab>CHILD
<tab><tab>SIBLING
Implementation:
Track parent nodes state: whenever a command enters a child node, push a parent
node onto an llist to remember the exact indentation characters used for that
level.
As soon as the first line on a child node is parsed, remember this new
indentation (which must have a longer strlen() than its parent level) to apply
to all remaining child siblings and grandchildren.
If the amount of spaces that indent a following VTY command are less than this
expected indentation, call vty_go_parent() until it matches up.
At any level, if the common length of indentation characters mismatch, abort
parsing in error.
Transitions to child node are spread across VTY implementations and are hard to
change. But transitions to the parent node are all handled by vty_go_parent().
By popping a parent from the list of parents in vty_go_parent(), we can also
detect that a command has changed the node without changing the parent, hence
it must have stepped into a child node, and we can push a parent frame.
The behavior on the interactive telnet VTY remains unchanged.
Change-Id: I24cbb3f6de111f2d31110c3c484c066f1153aac9
2017-09-07 01:08:06 +00:00
|
|
|
|
|
|
|
/*! List of parent nodes, last item is the outermost parent. */
|
|
|
|
struct llist_head parent_nodes;
|
|
|
|
|
|
|
|
/*! When reading from a config file, these are the indenting characters expected for children of
|
|
|
|
* the current VTY node. */
|
|
|
|
char *indent;
|
vty/command: fix: restrict the expert mode to the current session
Having the expert mode flag stored in the global 'host' structure
was a bad idea, because this way it applies globally. In other
words, if user Bob activates the expert mode in his dedicated
session (e.g. a telnet connection), then not only him, but all
other users would see the hidden commands in their VTYs.
Moreover, if somebody deactivates the expert mode, it would also
affect the Bob's VTY session. And finally, terminating a VTY
session would not deactivate the expert mode.
Let's move that flag from the global 'struct host' to 'struct vty'
representing an individual VTY session, so then the expert mode
would only affect the session where it was activated.
In functions related to the XML VTY reference generation we don't
have access to 'struct vty' (there may be no VTY session at all).
Add two additional arguments to vty_dump_nodes(), indicating the
global flag mask and a matching mode. This would allow to match
the VTY commands in many different ways, e.g. one can dump hidden
commands only, or all commands except the library specific ones.
Change-Id: Iba13f0949061e3dadf9cf92829d15e97074fe4ad
Related: SYS#4910
2020-10-25 09:34:57 +00:00
|
|
|
|
|
|
|
/*! Whether the expert mode is enabled. */
|
|
|
|
bool expert_mode;
|
2010-05-19 17:02:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Small macro to determine newline is newline only or linefeed needed. */
|
|
|
|
#define VTY_NEWLINE ((vty->type == VTY_TERM) ? "\r\n" : "\n")
|
|
|
|
|
2012-07-12 07:22:56 +00:00
|
|
|
static inline const char *vty_newline(struct vty *vty)
|
2010-05-19 17:02:52 +00:00
|
|
|
{
|
|
|
|
return VTY_NEWLINE;
|
|
|
|
}
|
|
|
|
|
2011-08-17 15:13:48 +00:00
|
|
|
/*! Information an application registers with the VTY */
|
2010-05-25 21:00:45 +00:00
|
|
|
struct vty_app_info {
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! name of the application */
|
2010-06-08 08:12:58 +00:00
|
|
|
const char *name;
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! version string of the application */
|
2010-06-08 08:12:58 +00:00
|
|
|
const char *version;
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! copyright string of the application */
|
2010-06-08 08:12:58 +00:00
|
|
|
const char *copyright;
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! \ref talloc context */
|
2010-05-25 21:00:45 +00:00
|
|
|
void *tall_ctx;
|
vty: track parent nodes also for telnet sessions
Keep track of parent nodes and go back hierarchically, not only for .cfg file
reading, but also for telnet VTY sessions.
A long time ago cfg file parsing was made strictly hierarchical: node exits go
back to parent nodes exactly as they were entered. However, live telnet VTY
sessions still lacked this and depended on the go_parent_cb().
From this commit on, implementing a go_parent_cb() is completely optional. The
go_parent_cb() no longer has the task to determine the correct parent node,
neither for cfg files (as already the case before this patch) nor for telnet
VTY sessions (added by this patch). Instead, a go_parent_cb() implementation
can merely take actions it requires on node exits, for example applying some
config when leaving a specific node.
The node value that is returned by the go_parent_cb() and the vty->node and
vty->index values that might be set are completely ignored; instead the
implicit parent node tracking determines the parent and node object.
As a side effect, the is_config_node() callback is no longer needed, since the
VTY now always implicitly knows when to exit back to the CONFIG_NODE.
For example, osmo_ss7_is_config_node() could now be dropped, and the
osmo_ss7_vty_go_parent() could be shortened by five switch cases, does no
longer need to set vty->node nor vty->index and could thus be shortened to:
int osmo_ss7_vty_go_parent(struct vty *vty)
{
struct osmo_ss7_asp *asp;
struct osmo_xua_server *oxs;
switch (vty->node) {
case L_CS7_ASP_NODE:
asp = vty->index;
/* If no local addr was set */
if (!asp->cfg.local.host_cnt) {
asp->cfg.local.host[0] = NULL;
asp->cfg.local.host_cnt = 1;
}
osmo_ss7_asp_restart(asp);
break;
case L_CS7_XUA_NODE:
oxs = vty->index;
/* If no local addr was set, or erased after _create(): */
if (!oxs->cfg.local.host_cnt)
osmo_ss7_xua_server_set_local_host(oxs, NULL);
if (osmo_ss7_xua_server_bind(oxs) < 0)
vty_out(vty, "%% Unable to bind xUA server to IP(s)%s", VTY_NEWLINE);
break;
}
return 0;
}
Before parent tracking, every program was required to write a go_parent_cb()
which has to return every node's parent node, basically a switch() statement
that manually traces the way back out of child nodes. If the go_parent_cb() has
errors, we may wildly jump around the node tree: a common error is to jump
right out to the top config node with one exit, even though we were N levels
deep. This kind of error has been eliminated for cfg files long ago, but still
exists for telnet VTY sessions, which this patch fixes.
This came up when I was adding multi-level config nodes to osmo-hlr to support
Distributed GSM / remote MS lookup: the config file worked fine, while vty node
tests failed to exit to the correct nodes.
Change-Id: I2b32b4fe20732728db6e9cdac7e484d96ab86dc5
2019-10-31 15:09:23 +00:00
|
|
|
/*! 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. */
|
2015-08-02 02:14:07 +00:00
|
|
|
int (*go_parent_cb)(struct vty *vty);
|
vty: track parent nodes also for telnet sessions
Keep track of parent nodes and go back hierarchically, not only for .cfg file
reading, but also for telnet VTY sessions.
A long time ago cfg file parsing was made strictly hierarchical: node exits go
back to parent nodes exactly as they were entered. However, live telnet VTY
sessions still lacked this and depended on the go_parent_cb().
From this commit on, implementing a go_parent_cb() is completely optional. The
go_parent_cb() no longer has the task to determine the correct parent node,
neither for cfg files (as already the case before this patch) nor for telnet
VTY sessions (added by this patch). Instead, a go_parent_cb() implementation
can merely take actions it requires on node exits, for example applying some
config when leaving a specific node.
The node value that is returned by the go_parent_cb() and the vty->node and
vty->index values that might be set are completely ignored; instead the
implicit parent node tracking determines the parent and node object.
As a side effect, the is_config_node() callback is no longer needed, since the
VTY now always implicitly knows when to exit back to the CONFIG_NODE.
For example, osmo_ss7_is_config_node() could now be dropped, and the
osmo_ss7_vty_go_parent() could be shortened by five switch cases, does no
longer need to set vty->node nor vty->index and could thus be shortened to:
int osmo_ss7_vty_go_parent(struct vty *vty)
{
struct osmo_ss7_asp *asp;
struct osmo_xua_server *oxs;
switch (vty->node) {
case L_CS7_ASP_NODE:
asp = vty->index;
/* If no local addr was set */
if (!asp->cfg.local.host_cnt) {
asp->cfg.local.host[0] = NULL;
asp->cfg.local.host_cnt = 1;
}
osmo_ss7_asp_restart(asp);
break;
case L_CS7_XUA_NODE:
oxs = vty->index;
/* If no local addr was set, or erased after _create(): */
if (!oxs->cfg.local.host_cnt)
osmo_ss7_xua_server_set_local_host(oxs, NULL);
if (osmo_ss7_xua_server_bind(oxs) < 0)
vty_out(vty, "%% Unable to bind xUA server to IP(s)%s", VTY_NEWLINE);
break;
}
return 0;
}
Before parent tracking, every program was required to write a go_parent_cb()
which has to return every node's parent node, basically a switch() statement
that manually traces the way back out of child nodes. If the go_parent_cb() has
errors, we may wildly jump around the node tree: a common error is to jump
right out to the top config node with one exit, even though we were N levels
deep. This kind of error has been eliminated for cfg files long ago, but still
exists for telnet VTY sessions, which this patch fixes.
This came up when I was adding multi-level config nodes to osmo-hlr to support
Distributed GSM / remote MS lookup: the config file worked fine, while vty node
tests failed to exit to the correct nodes.
Change-Id: I2b32b4fe20732728db6e9cdac7e484d96ab86dc5
2019-10-31 15:09:23 +00:00
|
|
|
/*! OBSOLETED: Implicit parent node tracking has replaced the use of this callback. This callback is no longer
|
|
|
|
* called, ever, and can be left NULL. */
|
2019-11-24 18:52:44 +00:00
|
|
|
int (*is_config_node)(struct vty *vty, int node)
|
|
|
|
OSMO_DEPRECATED("Implicit parent node tracking has replaced the use of this callback. This callback is"
|
|
|
|
" no longer called, ever, and can be left NULL.");
|
2017-06-19 22:17:59 +00:00
|
|
|
/*! Check if the config is consistent before write */
|
2014-11-21 09:40:07 +00:00
|
|
|
int (*config_is_consistent)(struct vty *vty);
|
2020-08-15 15:16:30 +00:00
|
|
|
/*! Description of the application specific VTY attributes (optional). */
|
2020-10-06 10:41:22 +00:00
|
|
|
const char * usr_attr_desc[VTY_CMD_USR_ATTR_NUM];
|
2020-08-15 15:16:30 +00:00
|
|
|
/*! Flag letters of the application specific VTY attributes (optional). */
|
2020-10-06 10:41:22 +00:00
|
|
|
char usr_attr_letters[VTY_CMD_USR_ATTR_NUM];
|
2010-05-25 21:00:45 +00:00
|
|
|
};
|
|
|
|
|
2010-05-19 17:02:52 +00:00
|
|
|
/* Prototypes. */
|
2010-05-25 21:00:45 +00:00
|
|
|
void vty_init(struct vty_app_info *app_info);
|
2010-05-19 17:02:52 +00:00
|
|
|
int vty_read_config_file(const char *file_name, void *priv);
|
2021-05-18 12:46:29 +00:00
|
|
|
int vty_read_config_filep(FILE *confp, void *priv);
|
2010-05-19 17:02:52 +00:00
|
|
|
void vty_init_vtysh (void);
|
|
|
|
void vty_reset (void);
|
|
|
|
struct vty *vty_new (void);
|
|
|
|
struct vty *vty_create (int vty_sock, void *priv);
|
2019-04-10 00:41:53 +00:00
|
|
|
bool vty_is_active(struct vty *vty);
|
2010-05-19 17:02:52 +00:00
|
|
|
int vty_out (struct vty *, const char *, ...) VTY_PRINTF_ATTRIBUTE(2, 3);
|
2019-02-01 04:38:44 +00:00
|
|
|
int vty_out_va(struct vty *vty, const char *format, va_list ap);
|
2010-05-19 17:02:52 +00:00
|
|
|
int vty_out_newline(struct vty *);
|
2021-09-05 21:08:59 +00:00
|
|
|
int vty_out_uptime(struct vty *vty, const struct timespec *starttime);
|
2010-05-19 17:02:52 +00:00
|
|
|
int vty_read(struct vty *vty);
|
|
|
|
//void vty_time_print (struct vty *, int);
|
|
|
|
void vty_close (struct vty *);
|
2021-09-09 13:42:32 +00:00
|
|
|
void vty_flush(struct vty *vty);
|
2010-05-19 17:02:52 +00:00
|
|
|
char *vty_get_cwd (void);
|
|
|
|
void vty_log (const char *level, const char *proto, const char *fmt, va_list);
|
|
|
|
int vty_config_lock (struct vty *);
|
|
|
|
int vty_config_unlock (struct vty *);
|
|
|
|
int vty_shell (struct vty *);
|
|
|
|
int vty_shell_serv (struct vty *);
|
|
|
|
void vty_hello (struct vty *);
|
2010-09-13 18:24:03 +00:00
|
|
|
void *vty_current_index(struct vty *);
|
|
|
|
int vty_current_node(struct vty *vty);
|
2015-08-02 02:14:07 +00:00
|
|
|
int vty_go_parent(struct vty *vty);
|
2010-05-19 17:02:52 +00:00
|
|
|
|
2016-02-23 13:01:41 +00:00
|
|
|
/* Return IP address passed to the 'line vty'/'bind' command, or "127.0.0.1" */
|
|
|
|
const char *vty_get_bind_addr(void);
|
2018-12-15 17:36:41 +00:00
|
|
|
/** Returns configured port passed to the 'line vty'/'bind' command or default_port. */
|
|
|
|
int vty_get_bind_port(int default_port);
|
2016-02-23 13:01:41 +00:00
|
|
|
|
2010-08-31 09:09:44 +00:00
|
|
|
extern void *tall_vty_ctx;
|
2011-08-17 15:13:48 +00:00
|
|
|
|
2011-09-04 20:56:10 +00:00
|
|
|
extern struct cmd_element cfg_description_cmd;
|
|
|
|
extern struct cmd_element cfg_no_description_cmd;
|
|
|
|
|
2013-10-10 18:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* signal handling
|
|
|
|
*/
|
|
|
|
enum signal_vty {
|
|
|
|
S_VTY_EVENT,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct vty_signal_data {
|
|
|
|
enum event event;
|
|
|
|
int sock;
|
|
|
|
struct vty *vty;
|
|
|
|
};
|
|
|
|
|
2012-04-18 19:53:23 +00:00
|
|
|
/*! @} */
|