input_complete(int arg UNUSED, int key UNUSED)
{
static int complete_flag;
- char buf[256];
+ char buf[256] = {};
if (rl_last_func != input_complete)
complete_flag = 0;
void
input_init(void)
{
+ retrieve_symbols();
+ printf("BIRD Client " BIRD_VERSION " ready.\n");
+
rl_readline_name = "birdc";
rl_add_defun("bird-complete", input_complete, '\t');
rl_add_defun("bird-help", input_help, '?');
if (!interactive)
return;
+ printf("BIRD Client Light " BIRD_VERSION " ready.\n");
+
if (tcgetattr(0, &stored_tty) < 0)
die("tcgetattr: %m");
#include "lib/string.h"
#include "client/client.h"
#include "sysdep/unix/unix.h"
+#include "client/reply_codes.h"
#define SERVER_READ_BUF_LEN 4096
static byte *server_read_pos = server_read_buf;
int init = 1; /* During intial sequence */
-int busy = 1; /* Executing BIRD command */
+int busy = 0; /* Executing BIRD command */
int interactive; /* Whether stdin is terminal */
static int num_lines, skip_input;
int term_lns, term_cls;
+static list symbols;
+static uint longest_symbol_len;
+
/*** Parsing of arguments ***/
for (i = optind; i < argc; i++)
len += strlen(argv[i]) + 1;
- tmp = init_cmd = malloc(len);
+ tmp = init_cmd = xmalloc(len);
for (i = optind; i < argc; i++)
{
strcpy(tmp, argv[i]);
tmp += strlen(tmp);
*tmp++ = ' ';
}
- tmp[-1] = 0;
+ tmp[-1] = 0; /* Put ending null-terminator */
once = 1;
interactive = 0;
puts("Press `?' for context sensitive help.");
return 1;
}
+ if (!strncmp(cmd, REFRESH_SYMBOLS_CMD, sizeof(REFRESH_SYMBOLS_CMD)-1))
+ {
+ retrieve_symbols();
+ return 1;
+ }
+
return 0;
}
free(cmd);
}
+static void
+add_to_symbols(int flag, const char *name)
+{
+ struct cli_symbol *sym = xmalloc(sizeof(struct cli_symbol));
+ sym->flags = flag;
+
+ sym->len = strlen(name);
+ char *name_ = xmalloc(sym->len + 1);
+ memcpy(name_, name, sym->len + 1);
+ sym->name = name_;
+ add_tail(&symbols, &sym->n);
+
+ if (longest_symbol_len < sym->len)
+ longest_symbol_len = sym->len;
+}
+
+void
+retrieve_symbols(void)
+{
+ /* purge old symbols */
+ list *syms = cli_get_symbol_list();
+ struct cli_symbol *sym, *next;
+ WALK_LIST_DELSAFE(sym, next, *syms)
+ {
+ rem2_node(&sym->n);
+ free((char *) sym->name);
+ free(sym);
+ }
+
+ add_to_symbols(CLI_SF_KW_ALL, "all");
+ add_to_symbols(CLI_SF_KW_OFF, "off");
+
+ submit_server_command(REFRESH_SYMBOLS_CMD);
+}
+
static void
init_commands(void)
{
exit(0);
}
+ init_list(&symbols);
+ longest_symbol_len = 1; /* Be careful, it's used as denominator! */
input_init();
term_lns = (term_lns > 0) ? term_lns : 25;
die("fcntl: %m");
}
+list *
+cli_get_symbol_list(void)
+{
+ return &symbols;
+}
+
+uint
+cli_get_symbol_maxlen(void)
+{
+ return longest_symbol_len;
+}
+
+static void
+server_got_symbol(int reply_code, const char *name)
+{
+ u32 flag = 0;
+
+ switch (reply_code)
+ {
+ case RC_CONSTANT_NAME: flag = CLI_SF_CONSTANT; break;
+ case RC_VARIABLE_NAME: flag = CLI_SF_VARIABLE; break;
+ case RC_FILTER_NAME: flag = CLI_SF_FILTER; break;
+ case RC_FUNCTION_NAME: flag = CLI_SF_FUNCTION; break;
+ case RC_PROTOCOL_NAME: flag = CLI_SF_PROTOCOL; break;
+ case RC_TABLE_NAME: flag = CLI_SF_TABLE; break;
+ case RC_TEMPLATE_NAME: flag = CLI_SF_TEMPLATE; break;
+ case RC_INTERFACE_NAME: flag = CLI_SF_INTERFACE; break;
+ default:
+ printf("Undefined %d: %s", reply_code, name);
+ return;
+ }
+
+ add_to_symbols(flag, name);
+}
#define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0)
static void
server_got_reply(char *x)
{
- int code;
+ int code = 0;
int len = 0;
if (*x == '+') /* Async reply */
sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 &&
(x[4] == ' ' || x[4] == '-'))
{
- if (code)
- PRINTF(len, "%s\n", verbose ? x : x+5);
+ if (code >= 3000 && code < 4000)
+ {
+ server_got_symbol(code, x+5);
+ }
+ else if (code)
+ {
+ PRINTF(len, "%s\n", verbose ? x : x+5);
+ }
if (x[4] == ' ')
{
- busy = 0;
- skip_input = 0;
- return;
+ busy = 0;
+ skip_input = 0;
+ return;
}
}
else
* Can be freely distributed and used under the terms of the GNU GPL.
*/
+#ifndef _BIRD_CLIENT_H_
+#define _BIRD_CLIENT_H_
+
+#define REFRESH_SYMBOLS_CMD "refresh symbols"
extern int init, busy, interactive;
extern int term_lns, term_cls;
/* client.c */
+/* Client Symbol Flags: Types */
+#define CLI_SF_CONSTANT (1 << 0)
+#define CLI_SF_VARIABLE (1 << 1)
+#define CLI_SF_FILTER (1 << 2)
+#define CLI_SF_FUNCTION (1 << 3)
+#define CLI_SF_PROTOCOL (1 << 4)
+#define CLI_SF_TABLE (1 << 5)
+#define CLI_SF_TEMPLATE (1 << 6)
+#define CLI_SF_INTERFACE (1 << 7)
+
+#define CLI_SF_OPTIONAL (1 << 8) /* This node is optional not mandatory */
+#define CLI_SF_PARAMETER (1 << 9) /* A parameter/word will follow after this node */
+
+/* Client Symbol Flags: Keywords */
+#define CLI_SF_KW_ALL (1 << 10)
+#define CLI_SF_KW_OFF (1 << 11)
+
+
+struct cli_symbol
+{
+ node n;
+ const char *name;
+ uint len;
+ u32 flags; /* CLI_SF_* */
+};
+
void submit_command(char *cmd_raw);
+void retrieve_symbols(void);
+void add_keywords_to_symbols(void);
+list *cli_get_symbol_list(void);
+uint cli_get_symbol_maxlen(void);
+
+#endif
#include "client/client.h"
struct cmd_info {
+ /* use for build tree and command cli */
char *command;
char *args;
char *help;
+
+ /* only for build tree */
int is_real_cmd;
+ u32 flags; /* Mask of (CLI_SF_*) */
};
static struct cmd_info command_table[] = {
};
struct cmd_node {
- struct cmd_node *sibling, *son, **plastson;
- struct cmd_info *cmd, *help;
- int len;
- signed char prio;
- char token[1];
+ struct cmd_node *sibling;
+ struct cmd_node *son;
+ struct cmd_node **plastson; /* Helping pointer to son */
+ struct cmd_info *cmd; /* Short info */
+ struct cmd_info *help; /* Detailed info */
+ signed char prio; /* Priority */
+ int len; /* Length of string in token */
+ u32 flags; /* Mask of (CLI_SF_*) */
+ char token[1]; /* Name of command */
};
static struct cmd_node cmd_root;
old->cmd = cmd;
else
old->help = cmd;
+ old->flags |= cmd->flags;
}
}
cmd_find_abbrev(struct cmd_node *root, char *cmd, int len, int *pambiguous)
{
struct cmd_node *m, *best = NULL, *best2 = NULL;
+ list *l_syms = cli_get_symbol_list();
+ struct cli_symbol *sym;
*pambiguous = 0;
for(m=root->son; m; m=m->sibling)
for(m=root->son; m; m=m->sibling)
if (m->len > len && !memcmp(m->token, cmd, len))
cmd_display_help(m->help, m->cmd);
+
+ struct cli_symbol *sym;
+ list *syms = cli_get_symbol_list();
+ WALK_LIST(sym, *syms)
+ {
+ if ((sym->flags & root->flags) && sym->len > len && memcmp(sym->name, cmd, len) == 0)
+ printf("%s\n", sym->name);
+ }
}
void
cmd_display_help(m->help, m->cmd);
}
+/*
+ * Return length of common prefix of all matches,
+ * Write count of all matches into pcount,
+ * Write common prefix string into buf
+ */
static int
cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, char *buf)
{
struct cmd_node *m;
- int best, best_prio, i;
+ int best, /* len of common prefix */
+ best_prio, i;
*pcount = 0;
best = -1;
(*pcount)++;
if (best < 0)
{
+ /* For a case that we'll have exactly one match */
strcpy(buf, m->token + len);
best = m->len - len;
best_prio = m->prio;
best = i;
}
}
+
+ list *syms = cli_get_symbol_list();
+ struct cli_symbol *sym;
+ WALK_LIST(sym, *syms)
+ {
+ if (!(sym->flags & root->flags))
+ continue;
+
+ if (sym->len < len || memcmp(sym->name, cmd, len))
+ continue;
+
+ (*pcount)++;
+
+ if (best < 0)
+ {
+ strcpy(buf, sym->name + len);
+ best = sym->len - len; /* for a case that we'll have only one match */
+ }
+ else
+ {
+ i = 0;
+ while (i < best && i < sym->len - len && buf[i] == sym->name[len+i])
+ i++;
+ best = i;
+ }
+ }
+
return best;
}
char *start = cmd;
char *end = cmd + len;
char *fin;
- struct cmd_node *n, *m;
+ struct cmd_node *n, *m = NULL;
char *z;
int ambig, cnt = 0, common;
/* Find the context */
n = &cmd_root;
- while (cmd < fin && n->son)
+ while (cmd < fin)
{
if (isspace(*cmd))
{
}
if (!m)
return -1;
- n = m;
+
+ /* Try skip a parameter/word */
+ if (m->flags & CLI_SF_PARAMETER)
+ {
+ z = cmd;
+
+ /* Skip spaces before parameter */
+ while (cmd < fin && isspace(*cmd))
+ cmd++;
+
+ /* Skip one parameter/word */
+ while (cmd < fin && !isspace(*cmd))
+ cmd++;
+
+ /* Check ending of parameter */
+ if (isspace(*cmd))
+ {
+ if (m->flags & CLI_SF_OPTIONAL)
+ m = n;
+ continue;
+ }
+ else
+ cmd = z;
+ }
+
+ /* Do not enter to optional command nodes */
+ if (!(m->flags & CLI_SF_OPTIONAL))
+ n = m;
}
- /* Completion of parameters is not yet supported */
- if (!n->son)
- return -1;
+ /* Enter to the last command node */
+ if (m && (m->flags & CLI_SF_PARAMETER))
+ n = m;
/* We know the context, let's try to complete */
common = cmd_find_common_match(n, fin, end-fin, &cnt, buf);
char *
cmd_expand(char *cmd)
{
- struct cmd_node *n, *m;
- char *c, *b, *args;
+ struct cmd_node *n, *m, *last_real_cmd = NULL;
+ char *c, *b, *args, *lrc_args = NULL;
int ambig;
args = c = cmd;
cmd_list_ambiguous(n, b, c-b);
return NULL;
}
+
args = c;
n = m;
+
+ if (m->cmd)
+ {
+ last_real_cmd = m;
+ lrc_args = c;
+ }
}
- if (!n->cmd)
+
+ if (!n->cmd && !last_real_cmd)
{
puts("No such command. Press `?' for help.");
return NULL;
}
+ if (last_real_cmd && last_real_cmd != n)
+ {
+ n = last_real_cmd;
+ args = lrc_args;
+ }
b = xmalloc(strlen(n->cmd->command) + strlen(args) + 1);
sprintf(b, "%s%s", n->cmd->command, args);
return b;
--- /dev/null
+/*
+ * BIRD Client -- Reply codes for communication between client and daemon
+ *
+ * (c) 2016 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_REPLY_CODES_H_
+#define _BIRD_REPLY_CODES_H_
+
+/*
+Reply codes of BIRD command-line interface
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+0xxx Action suceessfully completed
+1xxx Table entry
+2xxx Table heading
+3xxx Internal messages
+8xxx Run-time error
+9xxx Parse-time error
+<space> Continuation
++ Spontaneous printout
+*/
+
+enum reply_code {
+ RC_OK = 0,
+ RC_WELCOME = 1,
+ RC_READING_CONFIGURATION = 2,
+ RC_RECONFIGURED = 3,
+ RC_RECONFIGURATION_IN_PROGRESS = 4,
+ RC_RECONFIGURATION_ALREADY_IN_PROGRESS, QUEUEING = 5,
+ RC_RECONFIGURATION_IGNORED_SHUTTING_DOWN = 6,
+ RC_SHUTDOWN_ORDERED = 7,
+ RC_ALREADY_DISABLED = 8,
+ RC_DISABLED = 9,
+ RC_ALREADY_ENABLED = 10,
+ RC_ENABLED = 11,
+ RC_RESTARTED = 12,
+ RC_STATUS_REPORT = 13,
+ RC_ROUTE_COUNT = 14,
+ RC_RELOADING = 15,
+ RC_ACCESS_RESTRICTED = 16,
+ RC_RECONFIGURATION_ALREADY_IN_PROGRESS_REMOVING_QUEUED_CONFIG = 17,
+ RC_RECONFIGURATION_CONFIRMED = 18,
+ RC_NOTHING_TO_DO_CONFIGURE_UNDO_CONFIRM = 19,
+ RC_CONFIGURATION_OK = 20,
+ RC_UNDO_REQUESTED = 21,
+ RC_UNDO_SCHEDULED = 22,
+ RC_EVALUATION_OF_EXPRESSION = 23,
+ RC_GRACEFUL_RESTART_STATUS_REPORT = 24,
+
+ RC_BIRD_VERSION = 1000,
+ RC_INTERFACE_LIST = 1001,
+ RC_PROTOCOL_LIST = 1002,
+ RC_INTERFACE_ADDRESS = 1003,
+ RC_INTERFACE_FLAGS = 1004,
+ RC_INTERFACE_SUMMARY = 1005,
+ RC_PROTOCOL_DETAILS = 1006,
+ RC_ROUTE_LIST = 1007,
+ RC_ROUTE_DETAILS = 1008,
+ RC_STATIC_ROUTE_LIST = 1009,
+ RC_SYMBOL_LIST = 1010,
+ RC_UPTIME = 1011,
+ RC_ROUTE_EXTENDED_ATTRIBUTE_LIST = 1012,
+ RC_SHOW_OSPF_NEIGHBORS = 1013,
+ RC_SHOW_OSPF = 1014,
+ RC_SHOW_OSPF_INTERFACE = 1015,
+ RC_SHOW_OSPF_STATE_TOPOLOGY = 1016,
+ RC_SHOW_OSPF_LSADB = 1017,
+ RC_SHOW_MEMORY = 1018,
+ RC_SHOW_ROA_LIST = 1019,
+ RC_SHOW_BFD_SESSIONS = 1020,
+ RC_SHOW_RIP_INTERFACE = 1021,
+ RC_SHOW_RIP_NEIGHBORS = 1022,
+
+ RC_TABLE_NAME = 3001,
+ RC_PROTOCOL_NAME = 3002,
+ RC_FILTER_NAME = 3003,
+ RC_FUNCTION_NAME = 3004,
+ RC_CONSTANT_NAME = 3005,
+ RC_VARIABLE_NAME = 3006,
+ RC_TEMPLATE_NAME = 3007,
+ RC_INTERFACE_NAME = 3008,
+
+ RC_REPLY_TOO_LONG = 8000,
+ RC_ROUTE_NOT_FOUND = 8001,
+ RC_CONFIGURATION_FILE_ERROR = 8002,
+ RC_NO_PROTOCOLS_MATCH = 8003,
+ RC_STOPPED_DUE_TO_RECONFIGURATION = 8004,
+ RC_PROTOCOL_IS_DOWN_CANNOT_DUMP = 8005,
+ RC_RELOAD_FAILED = 8006,
+ RC_ACCESS_DENIED = 8007,
+ RC_EVALUATION_RUNTIME_ERROR = 8008,
+
+ RC_COMMAND_TOO_LONG = 9000,
+ RC_PARSE_ERROR = 9001,
+ RC_INVALID_SYMBOL_TYPE = 9002,
+};
+
+#endif
+
static inline int cf_symbol_is_constant(struct symbol *sym)
{ return (sym->class & 0xff00) == SYM_CONSTANT; }
+static inline int cf_symbol_is_variable(struct symbol *sym)
+{ return (sym->class & 0xff00) == SYM_VARIABLE; }
+
/* Parser */
# Can be freely distributed and used under the terms of the GNU GPL.
#
-m4_define(CF_CLI, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$3", "$4", 1 },
+m4_define(CF_CLI, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$3", "$4", 1, $5 },
m4_divert(-1)')
-m4_define(CF_CLI_CMD, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1 },
+m4_define(CF_CLI_CMD, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 1, 0 },
m4_divert(-1)')
-m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0 },
+m4_define(CF_CLI_HELP, `m4_divert(0){ "m4_translit($1,A-Z,a-z)", "$2", "$3", 0, $4 },
m4_divert(-1)')
# As we are processing C source, we must access all M4 primitives via
+++ /dev/null
-Reply codes of BIRD command-line interface
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-0xxx Action suceessfully completed
-1xxx Table entry
-2xxx Table heading
-8xxx Run-time error
-9xxx Parse-time error
-<space> Continuation
-+ Spontaneous printout
-
-0000 OK
-0001 Welcome
-0002 Reading configuration
-0003 Reconfigured
-0004 Reconfiguration in progress
-0005 Reconfiguration already in progress, queueing
-0006 Reconfiguration ignored, shutting down
-0007 Shutdown ordered
-0008 Already disabled
-0009 Disabled
-0010 Already enabled
-0011 Enabled
-0012 Restarted
-0013 Status report
-0014 Route count
-0015 Reloading
-0016 Access restricted
-0017 Reconfiguration already in progress, removing queued config
-0018 Reconfiguration confirmed
-0019 Nothing to do (configure undo/confirm)
-0020 Configuration OK
-0021 Undo requested
-0022 Undo scheduled
-0023 Evaluation of expression
-0024 Graceful restart status report
-
-1000 BIRD version
-1001 Interface list
-1002 Protocol list
-1003 Interface address
-1004 Interface flags
-1005 Interface summary
-1006 Protocol details
-1007 Route list
-1008 Route details
-1009 Static route list
-1010 Symbol list
-1011 Uptime
-1012 Route extended attribute list
-1013 Show ospf neighbors
-1014 Show ospf
-1015 Show ospf interface
-1016 Show ospf state/topology
-1017 Show ospf lsadb
-1018 Show memory
-1019 Show ROA list
-1020 Show BFD sessions
-1021 Show RIP interface
-1022 Show RIP neighbors
-
-8000 Reply too long
-8001 Route not found
-8002 Configuration file error
-8003 No protocols match
-8004 Stopped due to reconfiguration
-8005 Protocol is down => cannot dump
-8006 Reload failed
-8007 Access denied
-8008 Evaluation runtime error
-
-9000 Command too long
-9001 Parse error
-9002 Invalid symbol type
* white space character.
*
* Reply codes starting with 0 stand for `action successfully completed' messages,
- * 1 means `table entry', 8 `runtime error' and 9 `syntax error'.
+ * 1 means `table entry', 3 means `internal message`, 8 `runtime error' and 9
+ * `syntax error'.
*
* Each CLI session is internally represented by a &cli structure and a
* resource pool containing all resources associated with the connection,
q[-1] = '\n';
}
-static void
-cli_hello(cli *c)
-{
- cli_printf(c, 1, "BIRD " BIRD_VERSION " ready.");
- c->cont = NULL;
-}
-
static void
cli_free_out(cli *c)
{
ev_schedule(c->event);
}
-
+/* cli read hooks variables */
static byte *cli_rh_pos;
static uint cli_rh_len;
static int cli_rh_trick_flag;
c->event = ev_new(p);
c->event->hook = cli_event;
c->event->data = c;
- c->cont = cli_hello;
+ c->cont = NULL;
c->parser_pool = lp_new(c->pool, 4096);
c->rx_buf = mb_alloc(c->pool, CLI_RX_BUF_SIZE);
ev_schedule(c->event);
#include "lib/string.h"
#include "lib/resource.h"
#include "filter/filter.h"
+#include "client/reply_codes.h"
+#include "nest/iface.h"
extern int shutting_down;
extern int configuring;
}
}
+static int
+get_cli_code_for_sym(struct symbol *sym)
+{
+ if (cf_symbol_is_constant(sym))
+ return RC_CONSTANT_NAME;
+
+ if (cf_symbol_is_variable(sym))
+ return RC_VARIABLE_NAME;
+
+ switch (sym->class & 0xff)
+ {
+ case SYM_PROTO: return RC_PROTOCOL_NAME;
+ case SYM_TEMPLATE: return RC_TEMPLATE_NAME;
+ case SYM_FUNCTION: return RC_FUNCTION_NAME;
+ case SYM_FILTER: return RC_FILTER_NAME;
+ case SYM_TABLE: return RC_TABLE_NAME;
+ default:
+ log(L_ERR "Undefined class %d of %s", sym->class, sym->name);
+ }
+ return 0;
+}
+
+/*
+ * Send all symbols for autocomplete interactive Bird command line
+ */
+void
+cmd_send_symbols(void)
+{
+ int code, pos = 0;
+ struct symbol *sym = NULL;
+
+ while (sym = cf_walk_symbols(config, sym, &pos))
+ {
+ code = get_cli_code_for_sym(sym);
+ cli_msg(code, "%s", sym->name);
+ }
+
+ struct iface *i;
+ WALK_LIST(i, iface_list)
+ cli_msg(RC_INTERFACE_NAME, "\"%s\"", i->name);
+
+ cli_msg(0, "");
+}
+
static void
print_size(char *dsc, size_t val)
{
void cmd_show_status(void);
void cmd_show_symbols(struct sym_show_data *sym);
+void cmd_send_symbols(void);
void cmd_show_memory(void);
void cmd_eval(struct f_inst *expr);
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
+CF_KEYWORDS(REFRESH)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
CF_CLI(SHOW MEMORY,,, [[Show memory usage]])
{ cmd_show_memory(); } ;
-CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]])
+CF_CLI(SHOW PROTOCOLS, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocols]], CLI_SF_PROTOCOL)
{ proto_apply_cmd($3, proto_cmd_show, 0, 0); } ;
-CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]])
+CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [<protocol> | \"<pattern>\"], [[Show routing protocol details]], CLI_SF_PROTOCOL)
{ proto_apply_cmd($4, proto_cmd_show, 0, 1); } ;
optsym:
CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport|noexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]])
{ rt_show($3); } ;
+CF_CLI_HELP(SHOW ROUTE FOR, <prefix> | <ip> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
+CF_CLI_HELP(SHOW ROUTE TABLE, <table> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_TABLE)
+CF_CLI_HELP(SHOW ROUTE FILTER, <filter> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_FILTER)
+CF_CLI_HELP(SHOW ROUTE WHERE, <condition> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
+CF_CLI_HELP(SHOW ROUTE ALL, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW ROUTE PRIMARY, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW ROUTE FILTRED, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW ROUTE EXPORT, <protocol> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL)
+CF_CLI_HELP(SHOW ROUTE PREEXPORT, <protocol> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL)
+CF_CLI_HELP(SHOW ROUTE NOEXPORT, <protocol> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL)
+CF_CLI_HELP(SHOW ROUTE PROTOCOL, <protocol> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL)
+CF_CLI_HELP(SHOW ROUTE STATS, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW ROUTE COUNT, ...,, CLI_SF_OPTIONAL)
+
r_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct rt_show_data));
CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
-CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
+CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]], ~CLI_SF_OPTIONAL)
{ cmd_show_symbols($3); } ;
+CF_CLI_HELP(REFRESH, symbols, [[Check out new symbols from daemon for autocomplete in BIRD Client]])
+CF_CLI(REFRESH SYMBOLS,,, [[Check out new symbols from daemon for autocomplete in BIRD Client]])
+{ cmd_send_symbols(); } ;
+
sym_args:
/* empty */ {
$$ = cfg_allocz(sizeof(struct sym_show_data));
CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]])
{ protos_dump_all(); cli_msg(0, ""); } ;
-CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]])
+CF_CLI(EVAL, term, <expr>, [[Evaluate an expression]], CLI_SF_CONSTANT | CLI_SF_VARIABLE)
{ cmd_eval($2); } ;
CF_CLI_HELP(ECHO, ..., [[Control echoing of log messages]])
-CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug | trace | info | remote | warning | error | auth }) [<buffer-size>], [[Control echoing of log messages]]) {
+CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug | trace | info | remote | warning | error | auth }) [<buffer-size>], [[Control echoing of log messages]], CLI_SF_KW_ALL | CLI_SF_KW_OFF) {
cli_set_log_echo(this_cli, $2, $3);
cli_msg(0, "");
} ;
}
;
-CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]])
+CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
-CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]])
+CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
-CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
+CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
-CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
+CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
-CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])
+CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_IN); } ;
-CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]])
+CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just exported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
-CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]])
+CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | <pattern> | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL | CLI_SF_KW_OFF | CLI_SF_PARAMETER)
{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
-CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]])
+CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | <pattern> | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL | CLI_SF_KW_OFF | CLI_SF_PARAMETER)
{ proto_apply_cmd($2, proto_cmd_mrtdump, 1, $3); } ;
CF_CLI(RESTRICT,,,[[Restrict current CLI session to safe commands]])
CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); })
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
-CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol XXX]])
+CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol XXX]], CLI_SF_PROTOCOL)
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
-CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
+CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER)
{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
-CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
+CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER)
{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[Show information about reachable OSPF network topology]])
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
-CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [<name>], [[Show information about all OSPF network topology]])
+CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [<name>], [[Show information about all OSPF network topology]], CLI_SF_PROTOCOL)
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
CF_CLI_HELP(SHOW OSPF STATE, [all] [<name>], [[Show information about OSPF network state]])
-CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about reachable OSPF network state]])
+CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about reachable OSPF network state]], CLI_SF_PROTOCOL)
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
-CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [<name>], [[Show information about all OSPF network state]])
+CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [<name>], [[Show information about all OSPF network state]], CLI_SF_PROTOCOL)
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
-CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]);
-CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [lsid <id>] [self | router <id>] [<proto>], [[Show content of OSPF LSA database]])
+CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]])
+CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [lsid <id>] [self | router <id>] [<proto>], [[Show content of OSPF LSA database]], CLI_SF_PROTOCOL)
{ ospf_sh_lsadb($4); };
+CF_CLI_HELP(SHOW OSPF LSADB GLOBAL, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW OSPF LSADB AREA, <id> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
+CF_CLI_HELP(SHOW OSPF LSADB LINK, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW OSPF LSADB TYPE, <num> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
+CF_CLI_HELP(SHOW OSPF LSADB LSID, <num> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
+CF_CLI_HELP(SHOW OSPF LSADB SELF, ...,, CLI_SF_OPTIONAL)
+CF_CLI_HELP(SHOW OSPF LSADB ROUTER, <num> ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER)
lsadb_args:
/* empty */ {
{
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
byte cmsg_buf[CMSG_TX_SPACE];
- bzero(cmsg_buf, sizeof(cmsg_buf));
+ memset(cmsg_buf, 0, sizeof(cmsg_buf));
sockaddr dst = {};
sockaddr_fill(&dst, fam_to_af[s->fam], s->daddr, s->iface, s->dport);