diff --git a/client/birdc.c b/client/birdc.c index ccf758be..49da77d6 100644 --- a/client/birdc.c +++ b/client/birdc.c @@ -78,7 +78,7 @@ static int 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; @@ -140,6 +140,9 @@ input_help(int arg, int key UNUSED) 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, '?'); diff --git a/client/birdcl.c b/client/birdcl.c index 2d5e1067..8e374924 100644 --- a/client/birdcl.c +++ b/client/birdcl.c @@ -136,6 +136,8 @@ input_init(void) if (!interactive) return; + printf("BIRD Client Light " BIRD_VERSION " ready.\n"); + if (tcgetattr(0, &stored_tty) < 0) die("tcgetattr: %m"); diff --git a/client/client.c b/client/client.c index b938f344..85729010 100644 --- a/client/client.c +++ b/client/client.c @@ -34,6 +34,7 @@ #include "lib/string.h" #include "client/client.h" #include "sysdep/unix/unix.h" +#include "client/reply_codes.h" #define SERVER_READ_BUF_LEN 4096 @@ -47,12 +48,15 @@ static byte server_read_buf[SERVER_READ_BUF_LEN]; 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 ***/ @@ -94,14 +98,14 @@ parse_args(int argc, char **argv) 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; @@ -126,6 +130,12 @@ handle_internal_command(char *cmd) 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; } @@ -166,6 +176,41 @@ submit_command(char *cmd_raw) 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) { @@ -192,6 +237,8 @@ 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; @@ -256,13 +303,47 @@ server_connect(void) 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 */ @@ -273,14 +354,20 @@ server_got_reply(char *x) 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 diff --git a/client/client.h b/client/client.h index b194a772..033ab7b9 100644 --- a/client/client.h +++ b/client/client.h @@ -6,6 +6,10 @@ * 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; @@ -33,4 +37,36 @@ char *cmd_expand(char *cmd); /* 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 diff --git a/client/commands.c b/client/commands.c index 226ae048..a5d54f95 100644 --- a/client/commands.c +++ b/client/commands.c @@ -15,10 +15,14 @@ #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[] = { @@ -26,11 +30,15 @@ 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; @@ -77,6 +85,7 @@ cmd_build_tree(void) old->cmd = cmd; else old->help = cmd; + old->flags |= cmd->flags; } } @@ -102,6 +111,8 @@ static struct cmd_node * 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) @@ -133,6 +144,14 @@ cmd_list_ambiguous(struct cmd_node *root, char *cmd, int len) 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 @@ -169,11 +188,17 @@ cmd_help(char *cmd, int len) 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; @@ -195,6 +220,7 @@ cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, ch (*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; @@ -207,6 +233,33 @@ cmd_find_common_match(struct cmd_node *root, char *cmd, int len, int *pcount, ch 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; } @@ -216,7 +269,7 @@ cmd_complete(char *cmd, int len, char *buf, int again) 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; @@ -226,7 +279,7 @@ cmd_complete(char *cmd, int len, char *buf, int again) /* Find the context */ n = &cmd_root; - while (cmd < fin && n->son) + while (cmd < fin) { if (isspace(*cmd)) { @@ -248,12 +301,39 @@ cmd_complete(char *cmd, int len, char *buf, int again) } 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); @@ -281,8 +361,8 @@ cmd_complete(char *cmd, int len, char *buf, int again) 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; @@ -306,14 +386,27 @@ cmd_expand(char *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; diff --git a/client/reply_codes.h b/client/reply_codes.h new file mode 100644 index 00000000..5fd399e8 --- /dev/null +++ b/client/reply_codes.h @@ -0,0 +1,101 @@ +/* + * 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 + 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 + diff --git a/conf/conf.h b/conf/conf.h index 8e490c7b..c6599666 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -158,6 +158,9 @@ char *cf_symbol_class_name(struct symbol *sym); 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 */ diff --git a/conf/gen_commands.m4 b/conf/gen_commands.m4 index 3ed21f13..d5779ffe 100644 --- a/conf/gen_commands.m4 +++ b/conf/gen_commands.m4 @@ -7,13 +7,13 @@ m4_divert(-1)m4_dnl # 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 diff --git a/doc/reply_codes b/doc/reply_codes deleted file mode 100644 index 79a7eb92..00000000 --- a/doc/reply_codes +++ /dev/null @@ -1,73 +0,0 @@ -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 - 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 diff --git a/nest/cli.c b/nest/cli.c index 83e79616..d6c36636 100644 --- a/nest/cli.c +++ b/nest/cli.c @@ -27,7 +27,8 @@ * 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, @@ -196,13 +197,6 @@ cli_copy_message(cli *c) 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) { @@ -228,7 +222,7 @@ cli_written(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; @@ -312,7 +306,7 @@ cli_new(void *priv) 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); diff --git a/nest/cmds.c b/nest/cmds.c index 82fdca66..f3edf2a4 100644 --- a/nest/cmds.c +++ b/nest/cmds.c @@ -15,6 +15,8 @@ #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; @@ -64,6 +66,50 @@ cmd_show_symbols(struct sym_show_data *sd) } } +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) { diff --git a/nest/cmds.h b/nest/cmds.h index 4cf8fb1b..7191166c 100644 --- a/nest/cmds.h +++ b/nest/cmds.h @@ -15,5 +15,6 @@ struct f_inst; 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); diff --git a/nest/config.Y b/nest/config.Y index 6bb686c3..b83e72cd 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -72,6 +72,7 @@ CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) 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) @@ -468,10 +469,10 @@ CF_CLI(SHOW STATUS,,, [[Show router status]]) CF_CLI(SHOW MEMORY,,, [[Show memory usage]]) { cmd_show_memory(); } ; -CF_CLI(SHOW PROTOCOLS, proto_patt2, [ | \"\"], [[Show routing protocols]]) +CF_CLI(SHOW PROTOCOLS, proto_patt2, [ | \"\"], [[Show routing protocols]], CLI_SF_PROTOCOL) { proto_apply_cmd($3, proto_cmd_show, 0, 0); } ; -CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show routing protocol details]]) +CF_CLI(SHOW PROTOCOLS ALL, proto_patt2, [ | \"\"], [[Show routing protocol details]], CLI_SF_PROTOCOL) { proto_apply_cmd($4, proto_cmd_show, 0, 1); } ; optsym: @@ -489,6 +490,20 @@ CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]]) CF_CLI(SHOW ROUTE, r_args, [[[|for |for ] [table ] [filter |where ] [all] [primary] [filtered] [(export|preexport|noexport)

] [protocol

] [stats|count]]], [[Show routing table]]) { rt_show($3); } ; +CF_CLI_HELP(SHOW ROUTE FOR, | ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER) +CF_CLI_HELP(SHOW ROUTE TABLE, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_TABLE) +CF_CLI_HELP(SHOW ROUTE FILTER, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_FILTER) +CF_CLI_HELP(SHOW ROUTE WHERE, ...,, 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, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL) +CF_CLI_HELP(SHOW ROUTE PREEXPORT, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL) +CF_CLI_HELP(SHOW ROUTE NOEXPORT, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER | CLI_SF_PROTOCOL) +CF_CLI_HELP(SHOW ROUTE 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)); @@ -568,9 +583,13 @@ export_mode: CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]]) -CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|], [[Show all known symbolic names]]) +CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|], [[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)); @@ -602,11 +621,11 @@ CF_CLI(DUMP ROUTES,,, [[Dump routing table]]) CF_CLI(DUMP PROTOCOLS,,, [[Dump protocol information]]) { protos_dump_all(); cli_msg(0, ""); } ; -CF_CLI(EVAL, term, , [[Evaluate an expression]]) +CF_CLI(EVAL, term, , [[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 }) [], [[Control echoing of log messages]]) { +CF_CLI(ECHO, echo_mask echo_size, (all | off | { debug | trace | info | remote | warning | error | auth }) [], [[Control echoing of log messages]], CLI_SF_KW_ALL | CLI_SF_KW_OFF) { cli_set_log_echo(this_cli, $2, $3); cli_msg(0, ""); } ; @@ -625,25 +644,25 @@ echo_size: } ; -CF_CLI(DISABLE, proto_patt, | \"\" | all, [[Disable protocol]]) +CF_CLI(DISABLE, proto_patt, | \"\" | all, [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) { proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; -CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]]) +CF_CLI(ENABLE, proto_patt, | \"\" | all, [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) { proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; -CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]]) +CF_CLI(RESTART, proto_patt, | \"\" | all, [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) { proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; -CF_CLI(RELOAD, proto_patt, | \"\" | all, [[Reload protocol]]) +CF_CLI(RELOAD, proto_patt, | \"\" | 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, | \"\" | all, [[Reload protocol (just imported routes)]]) +CF_CLI(RELOAD IN, proto_patt, | \"\" | 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, | \"\" | all, [[Reload protocol (just exported routes)]]) +CF_CLI(RELOAD OUT, proto_patt, | \"\" | 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, ( | | all) (all | off | { states | routes | filters | interfaces | events | packets }), [[Control protocol debugging via BIRD logs]]) +CF_CLI(DEBUG, proto_patt debug_mask, ( | | 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, ( | | all) (all | off | { states | messages }), [[Control protocol debugging via MRTdump format]]) +CF_CLI(MRTDUMP, proto_patt mrtdump_mask, ( | | 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]]) diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 297774b5..522ab52b 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -417,13 +417,13 @@ CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEM 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, [], [[Show information about OSPF protocol XXX]]) +CF_CLI(SHOW OSPF, optsym, [], [[Show information about OSPF protocol XXX]], CLI_SF_PROTOCOL) { ospf_sh(proto_get_named($3, &proto_ospf)); }; -CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [] [\"\"], [[Show information about OSPF neighbors]]) +CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [] [\"\"], [[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, [] [\"\"], [[Show information about interface]]) +CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [] [\"\"], [[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] [], [[Show information about OSPF network topology]]) @@ -431,20 +431,27 @@ CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [], [[Show information about OSPF ne CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [], [[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, [], [[Show information about all OSPF network topology]]) +CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [], [[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] [], [[Show information about OSPF network state]]) -CF_CLI(SHOW OSPF STATE, optsym opttext, [], [[Show information about reachable OSPF network state]]) +CF_CLI(SHOW OSPF STATE, optsym opttext, [], [[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, [], [[Show information about all OSPF network state]]) +CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [], [[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 | link] [type ] [lsid ] [self | router ] [], [[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 | link] [type ] [lsid ] [self | router ] [], [[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, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER) +CF_CLI_HELP(SHOW OSPF LSADB LINK, ...,, CLI_SF_OPTIONAL) +CF_CLI_HELP(SHOW OSPF LSADB TYPE, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER) +CF_CLI_HELP(SHOW OSPF LSADB LSID, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER) +CF_CLI_HELP(SHOW OSPF LSADB SELF, ...,, CLI_SF_OPTIONAL) +CF_CLI_HELP(SHOW OSPF LSADB ROUTER, ...,, CLI_SF_OPTIONAL | CLI_SF_PARAMETER) lsadb_args: /* empty */ { diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index cbfb47d5..1674a198 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1564,7 +1564,7 @@ sk_sendmsg(sock *s) { 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);