]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
lib: fix possible assert() fail in zlog_fd()
[mirror_frr.git] / lib / command.c
CommitLineData
274a4a44 1/*
9547b5d0
QY
2 * CLI backend interface.
3 *
4 * --
5 * Copyright (C) 2016 Cumulus Networks, Inc.
6 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 * Copyright (C) 2013 by Open Source Routing.
8 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
9 *
10 * This file is part of GNU Zebra.
11 *
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
15 * later version.
16 *
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
896014f4
DL
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
9547b5d0 25 */
718e3744 26
27#include <zebra.h>
fe011935 28#include <lib/version.h>
718e3744 29
fe011935
QY
30#include "command.h"
31#include "frrstr.h"
718e3744 32#include "memory.h"
33#include "log.h"
0bdeb5e5 34#include "log_vty.h"
9ab6812d 35#include "thread.h"
b21b19c5 36#include "vector.h"
d0bfb22c 37#include "linklist.h"
b21b19c5 38#include "vty.h"
354d119a 39#include "workqueue.h"
19dc275e 40#include "vrf.h"
d0bfb22c 41#include "command_match.h"
5894e76d 42#include "command_graph.h"
1bf9f027 43#include "qobj.h"
8efe88ea 44#include "defaults.h"
9eed278b 45#include "libfrr.h"
bd74dc61 46#include "jhash.h"
01e24c4a 47#include "hook.h"
481bc15f 48#include "lib_errors.h"
1c2facd1 49#include "northbound_cli.h"
5920b3eb 50#include "network.h"
d0bfb22c 51
3d19ffc5
QY
52#include "frrscript.h"
53
bf8d3d6a
DL
54DEFINE_MTYPE_STATIC(LIB, HOST, "Host config");
55DEFINE_MTYPE(LIB, COMPLETION, "Completion item");
4a1ab8e4 56
26fbe472
QY
57#define item(x) \
58 { \
59 x, #x \
60 }
61
62/* clang-format off */
63const struct message tokennames[] = {
64 item(WORD_TKN),
65 item(VARIABLE_TKN),
66 item(RANGE_TKN),
67 item(IPV4_TKN),
68 item(IPV4_PREFIX_TKN),
69 item(IPV6_TKN),
70 item(IPV6_PREFIX_TKN),
71 item(MAC_TKN),
72 item(MAC_PREFIX_TKN),
73 item(FORK_TKN),
74 item(JOIN_TKN),
75 item(START_TKN),
76 item(END_TKN),
77 {0},
78};
26fbe472 79/* clang-format on */
a83a5331 80
718e3744 81/* Command vector which includes some level of command lists. Normally
82 each daemon maintains each own cmdvec. */
eb820afe 83vector cmdvec = NULL;
718e3744 84
85/* Host information structure. */
86struct host host;
87
419cd5a0
MK
88/*
89 * Returns host.name if any, otherwise
90 * it returns the system hostname.
91 */
6b3ee3a0 92const char *cmd_hostname_get(void)
419cd5a0
MK
93{
94 return host.name;
95}
96
97/*
98 * Returns unix domainname
99 */
6b3ee3a0 100const char *cmd_domainname_get(void)
419cd5a0
MK
101{
102 return host.domainname;
103}
104
791ded4a
DL
105static int root_on_exit(struct vty *vty);
106
718e3744 107/* Standard command node structures. */
d62a17ae 108static struct cmd_node auth_node = {
f4b8291f 109 .name = "auth",
62b346ee
DL
110 .node = AUTH_NODE,
111 .prompt = "Password: ",
718e3744 112};
113
d62a17ae 114static struct cmd_node view_node = {
f4b8291f 115 .name = "view",
62b346ee
DL
116 .node = VIEW_NODE,
117 .prompt = "%s> ",
791ded4a 118 .node_exit = root_on_exit,
718e3744 119};
120
d62a17ae 121static struct cmd_node auth_enable_node = {
f4b8291f 122 .name = "auth enable",
62b346ee
DL
123 .node = AUTH_ENABLE_NODE,
124 .prompt = "Password: ",
718e3744 125};
126
d62a17ae 127static struct cmd_node enable_node = {
f4b8291f 128 .name = "enable",
62b346ee
DL
129 .node = ENABLE_NODE,
130 .prompt = "%s# ",
791ded4a 131 .node_exit = root_on_exit,
718e3744 132};
133
612c2c15 134static int config_write_host(struct vty *vty);
62b346ee 135static struct cmd_node config_node = {
f4b8291f 136 .name = "config",
62b346ee 137 .node = CONFIG_NODE,
24389580 138 .parent_node = ENABLE_NODE,
62b346ee 139 .prompt = "%s(config)# ",
612c2c15 140 .config_write = config_write_host,
791ded4a 141 .node_exit = vty_config_node_exit,
62b346ee 142};
6590f2c3 143
dd90823b
CS
144static bool vty_check_node_for_xpath_decrement(enum node_type target_node,
145 enum node_type node)
146{
147 /* bgp afi-safi (`address-family <afi> <safi>`) node
148 * does not increment xpath_index.
149 * In order to use (`router bgp`) BGP_NODE's xpath as a base,
150 * retain xpath_index as 1 upon exiting from
151 * afi-safi node.
152 */
153
154 if (target_node == BGP_NODE
155 && (node == BGP_IPV4_NODE || node == BGP_IPV6_NODE
156 || node == BGP_IPV4M_NODE || node == BGP_IPV6M_NODE
157 || node == BGP_VPNV4_NODE || node == BGP_VPNV6_NODE
158 || node == BGP_EVPN_NODE || node == BGP_IPV4L_NODE
1e93fbed
DS
159 || node == BGP_IPV6L_NODE || node == BGP_FLOWSPECV4_NODE
160 || node == BGP_FLOWSPECV6_NODE))
dd90823b
CS
161 return false;
162
163 return true;
164}
165
cb585b65 166/* This is called from main when a daemon is invoked with -v or --version. */
d62a17ae 167void print_version(const char *progname)
6590f2c3 168{
d62a17ae 169 printf("%s version %s\n", progname, FRR_VERSION);
170 printf("%s\n", FRR_COPYRIGHT);
e063f271 171#ifdef ENABLE_VERSION_BUILD_CONFIG
d62a17ae 172 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
e063f271 173#endif
6590f2c3 174}
175
d62a17ae 176char *argv_concat(struct cmd_token **argv, int argc, int shift)
177{
a6a87d63 178 int cnt = MAX(argc - shift, 0);
179 const char *argstr[cnt + 1];
180
181 if (!cnt)
182 return NULL;
fe011935
QY
183
184 for (int i = 0; i < cnt; i++)
185 argstr[i] = argv[i + shift]->arg;
186
187 return frrstr_join(argstr, cnt, " ");
188}
189
190vector cmd_make_strvec(const char *string)
191{
192 if (!string)
d62a17ae 193 return NULL;
fe011935
QY
194
195 const char *copy = string;
196
197 /* skip leading whitespace */
fefa5e0f 198 while (isspace((unsigned char)*copy) && *copy != '\0')
fe011935
QY
199 copy++;
200
201 /* if the entire string was whitespace or a comment, return */
202 if (*copy == '\0' || *copy == '!' || *copy == '#')
203 return NULL;
204
0a334343 205 vector result = frrstr_split_vec(copy, "\n\r\t ");
fe011935
QY
206
207 for (unsigned int i = 0; i < vector_active(result); i++) {
208 if (strlen(vector_slot(result, i)) == 0) {
209 XFREE(MTYPE_TMP, vector_slot(result, i));
f428cb8a 210 vector_unset(result, i);
fe011935 211 }
d62a17ae 212 }
f428cb8a
QY
213
214 vector_compact(result);
215
fe011935
QY
216 return result;
217}
218
219void cmd_free_strvec(vector v)
220{
221 frrstr_strvec_free(v);
718e3744 222}
223
ae19d7dd
QY
224/**
225 * Convenience function for accessing argv data.
226 *
227 * @param argc
228 * @param argv
229 * @param text definition snippet of the desired token
230 * @param index the starting index, and where to store the
231 * index of the found token if it exists
232 * @return 1 if found, 0 otherwise
233 */
d62a17ae 234int argv_find(struct cmd_token **argv, int argc, const char *text, int *index)
ae19d7dd 235{
d62a17ae 236 int found = 0;
237 for (int i = *index; i < argc && found == 0; i++)
238 if ((found = strmatch(text, argv[i]->text)))
239 *index = i;
240 return found;
ae19d7dd
QY
241}
242
d8b87afe 243static unsigned int cmd_hash_key(const void *p)
274f29b2 244{
bd74dc61
DS
245 int size = sizeof(p);
246
247 return jhash(p, size, 0);
274f29b2
PJ
248}
249
74df8d6d 250static bool cmd_hash_cmp(const void *a, const void *b)
274f29b2 251{
d62a17ae 252 return a == b;
274f29b2
PJ
253}
254
718e3744 255/* Install top node of command vector. */
612c2c15 256void install_node(struct cmd_node *node)
718e3744 257{
d62a17ae 258 vector_set_index(cmdvec, node->node, node);
d62a17ae 259 node->cmdgraph = graph_new();
260 node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
261 // add start node
262 struct cmd_token *token =
263 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
264 graph_new_node(node->cmdgraph, token,
265 (void (*)(void *)) & cmd_token_del);
996c9314 266 node->cmd_hash = hash_create_size(16, cmd_hash_key, cmd_hash_cmp,
bd74dc61 267 "Command Hash");
718e3744 268}
269
718e3744 270/* Return prompt character of specified node. */
d62a17ae 271const char *cmd_prompt(enum node_type node)
718e3744 272{
d62a17ae 273 struct cmd_node *cnode;
718e3744 274
d62a17ae 275 cnode = vector_slot(cmdvec, node);
276 return cnode->prompt;
718e3744 277}
278
279/* Install a command into a node. */
01485adb 280void _install_element(enum node_type ntype, const struct cmd_element *cmd)
718e3744 281{
d62a17ae 282 struct cmd_node *cnode;
d0bfb22c 283
d62a17ae 284 /* cmd_init hasn't been called */
285 if (!cmdvec) {
286 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
287 __func__);
288 return;
289 }
ebacb4ed 290
3cbb67f2 291 cnode = vector_lookup(cmdvec, ntype);
718e3744 292
d62a17ae 293 if (cnode == NULL) {
294 fprintf(stderr,
3cbb67f2 295 "%s[%s]:\n"
f4b8291f 296 "\tnode %d does not exist.\n"
3cbb67f2 297 "\tplease call install_node() before install_element()\n",
f4b8291f 298 cmd->name, cmd->string, ntype);
d62a17ae 299 exit(EXIT_FAILURE);
300 }
ebacb4ed 301
154e9ca1 302 if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) {
d62a17ae 303 fprintf(stderr,
3cbb67f2
DL
304 "%s[%s]:\n"
305 "\tnode %d (%s) already has this command installed.\n"
306 "\tduplicate install_element call?\n",
f4b8291f 307 cmd->name, cmd->string, ntype, cnode->name);
d62a17ae 308 return;
309 }
ebacb4ed 310
154e9ca1 311 assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
ebacb4ed 312
d62a17ae 313 struct graph *graph = graph_new();
314 struct cmd_token *token =
315 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
316 graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
de8f7a39 317
d62a17ae 318 cmd_graph_parse(graph, cmd);
319 cmd_graph_names(graph);
320 cmd_graph_merge(cnode->cmdgraph, graph, +1);
321 graph_delete_graph(graph);
de8f7a39 322
154e9ca1 323 vector_set(cnode->cmd_vector, (void *)cmd);
735e62a0 324
d62a17ae 325 if (ntype == VIEW_NODE)
01485adb 326 _install_element(ENABLE_NODE, cmd);
718e3744 327}
328
154e9ca1 329void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
de8f7a39 330{
d62a17ae 331 struct cmd_node *cnode;
de8f7a39 332
d62a17ae 333 /* cmd_init hasn't been called */
334 if (!cmdvec) {
335 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
336 __func__);
337 return;
338 }
de8f7a39 339
3cbb67f2 340 cnode = vector_lookup(cmdvec, ntype);
de8f7a39 341
d62a17ae 342 if (cnode == NULL) {
343 fprintf(stderr,
3cbb67f2 344 "%s[%s]:\n"
f4b8291f 345 "\tnode %d does not exist.\n"
3cbb67f2 346 "\tplease call install_node() before uninstall_element()\n",
f4b8291f 347 cmd->name, cmd->string, ntype);
d62a17ae 348 exit(EXIT_FAILURE);
349 }
de8f7a39 350
154e9ca1 351 if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) {
d62a17ae 352 fprintf(stderr,
3cbb67f2
DL
353 "%s[%s]:\n"
354 "\tnode %d (%s) does not have this command installed.\n"
355 "\tduplicate uninstall_element call?\n",
f4b8291f 356 cmd->name, cmd->string, ntype, cnode->name);
d62a17ae 357 return;
358 }
de8f7a39 359
154e9ca1 360 vector_unset_value(cnode->cmd_vector, (void *)cmd);
de8f7a39 361
d62a17ae 362 struct graph *graph = graph_new();
363 struct cmd_token *token =
364 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
365 graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
de8f7a39 366
d62a17ae 367 cmd_graph_parse(graph, cmd);
368 cmd_graph_names(graph);
369 cmd_graph_merge(cnode->cmdgraph, graph, -1);
370 graph_delete_graph(graph);
de8f7a39 371
d62a17ae 372 if (ntype == VIEW_NODE)
373 uninstall_element(ENABLE_NODE, cmd);
de8f7a39
DL
374}
375
376
2d362d10 377static const unsigned char itoa64[] =
d62a17ae 378 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
718e3744 379
d62a17ae 380static void to64(char *s, long v, int n)
718e3744 381{
d62a17ae 382 while (--n >= 0) {
383 *s++ = itoa64[v & 0x3f];
384 v >>= 6;
385 }
718e3744 386}
387
d62a17ae 388static char *zencrypt(const char *passwd)
718e3744 389{
d62a17ae 390 char salt[6];
391 struct timeval tv;
392 char *crypt(const char *, const char *);
718e3744 393
d62a17ae 394 gettimeofday(&tv, 0);
d0bfb22c 395
5920b3eb 396 to64(&salt[0], frr_weak_random(), 3);
d62a17ae 397 to64(&salt[3], tv.tv_usec, 3);
398 salt[5] = '\0';
718e3744 399
d62a17ae 400 return crypt(passwd, salt);
718e3744 401}
402
0bdeb5e5
DL
403static bool full_cli;
404
718e3744 405/* This function write configuration of this host. */
d62a17ae 406static int config_write_host(struct vty *vty)
407{
6b3ee3a0
MK
408 if (cmd_hostname_get())
409 vty_out(vty, "hostname %s\n", cmd_hostname_get());
d62a17ae 410
3b103fec
MK
411 if (cmd_domainname_get())
412 vty_out(vty, "domainname %s\n", cmd_domainname_get());
413
0204baa8 414 /* The following are all configuration commands that are not sent to
3518f352
DS
415 * watchfrr. For instance watchfrr is hardcoded to log to syslog so
416 * we would always display 'log syslog informational' in the config
417 * which would cause other daemons to then switch to syslog when they
418 * parse frr.conf.
419 */
0bdeb5e5 420 if (full_cli) {
0204baa8
DW
421 if (host.encrypt) {
422 if (host.password_encrypt)
3518f352
DS
423 vty_out(vty, "password 8 %s\n",
424 host.password_encrypt);
0204baa8
DW
425 if (host.enable_encrypt)
426 vty_out(vty, "enable password 8 %s\n",
427 host.enable_encrypt);
428 } else {
429 if (host.password)
430 vty_out(vty, "password %s\n", host.password);
431 if (host.enable)
3518f352
DS
432 vty_out(vty, "enable password %s\n",
433 host.enable);
0204baa8 434 }
0bdeb5e5 435 log_config_write(vty);
d62a17ae 436
0204baa8
DW
437 if (host.advanced)
438 vty_out(vty, "service advanced-vty\n");
d62a17ae 439
0204baa8
DW
440 if (host.encrypt)
441 vty_out(vty, "service password-encryption\n");
d62a17ae 442
0204baa8 443 if (host.lines >= 0)
3518f352
DS
444 vty_out(vty, "service terminal-length %d\n",
445 host.lines);
d62a17ae 446
0204baa8
DW
447 if (host.motdfile)
448 vty_out(vty, "banner motd file %s\n", host.motdfile);
19d61463
DA
449 else if (host.motd
450 && strncmp(host.motd, FRR_DEFAULT_MOTD,
451 strlen(host.motd)))
452 vty_out(vty, "banner motd line %s\n", host.motd);
0204baa8
DW
453 else if (!host.motd)
454 vty_out(vty, "no banner motd\n");
455 }
d62a17ae 456
9eed278b
DL
457 if (debug_memstats_at_exit)
458 vty_out(vty, "!\ndebug memstats-at-exit\n");
459
d62a17ae 460 return 1;
718e3744 461}
462
d0bfb22c 463/* Utility function for getting command graph. */
d62a17ae 464static struct graph *cmd_node_graph(vector v, enum node_type ntype)
718e3744 465{
d62a17ae 466 struct cmd_node *cnode = vector_slot(v, ntype);
467 return cnode->cmdgraph;
718e3744 468}
469
d62a17ae 470static int cmd_try_do_shortcut(enum node_type node, char *first_word)
471{
472 if (first_word != NULL && node != AUTH_NODE && node != VIEW_NODE
473 && node != AUTH_ENABLE_NODE && 0 == strcmp("do", first_word))
474 return 1;
475 return 0;
718e3744 476}
477
d0bfb22c
QY
478/**
479 * Compare function for cmd_token.
480 * Used with qsort to sort command completions.
481 */
d62a17ae 482static int compare_completions(const void *fst, const void *snd)
718e3744 483{
36de6e0e
A
484 const struct cmd_token *first = *(const struct cmd_token * const *)fst,
485 *secnd = *(const struct cmd_token * const *)snd;
d62a17ae 486 return strcmp(first->text, secnd->text);
718e3744 487}
488
d0bfb22c
QY
489/**
490 * Takes a list of completions returned by command_complete,
491 * dedeuplicates them based on both text and description,
6011c1b2
QY
492 * sorts them, and returns them as a vector.
493 *
494 * @param completions linked list of cmd_token
495 * @return deduplicated and sorted vector with
d0bfb22c 496 */
d62a17ae 497vector completions_to_vec(struct list *completions)
498{
499 vector comps = vector_init(VECTOR_MIN_SIZE);
500
501 struct listnode *ln;
502 struct cmd_token *token, *cr = NULL;
503 unsigned int i, exists;
504 for (ALL_LIST_ELEMENTS_RO(completions, ln, token)) {
505 if (token->type == END_TKN && (cr = token))
506 continue;
507
508 // linear search for token in completions vector
509 exists = 0;
510 for (i = 0; i < vector_active(comps) && !exists; i++) {
511 struct cmd_token *curr = vector_slot(comps, i);
53205694 512#ifdef VTYSH_DEBUG
d62a17ae 513 exists = !strcmp(curr->text, token->text)
514 && !strcmp(curr->desc, token->desc);
53205694 515#else
d62a17ae 516 exists = !strcmp(curr->text, token->text);
53205694 517#endif /* VTYSH_DEBUG */
d62a17ae 518 }
909a2155 519
d62a17ae 520 if (!exists)
521 vector_set(comps, token);
522 }
cd40b329 523
d62a17ae 524 // sort completions
525 qsort(comps->index, vector_active(comps), sizeof(void *),
526 &compare_completions);
cd40b329 527
d62a17ae 528 // make <cr> the first element, if it is present
529 if (cr) {
530 vector_set_index(comps, vector_active(comps), NULL);
531 memmove(comps->index + 1, comps->index,
532 (comps->alloced - 1) * sizeof(void *));
533 vector_set_index(comps, 0, cr);
534 }
6011c1b2 535
d62a17ae 536 return comps;
cd40b329 537}
d0bfb22c
QY
538/**
539 * Generates a vector of cmd_token representing possible completions
540 * on the current input.
541 *
542 * @param vline the vectorized input line
543 * @param vty the vty with the node to match on
544 * @param status pointer to matcher status code
ebacb4ed 545 * @return vector of struct cmd_token * with possible completions
d0bfb22c 546 */
d62a17ae 547static vector cmd_complete_command_real(vector vline, struct vty *vty,
548 int *status)
cd40b329 549{
d62a17ae 550 struct list *completions;
551 struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
cd40b329 552
d62a17ae 553 enum matcher_rv rv = command_complete(cmdgraph, vline, &completions);
cd40b329 554
d62a17ae 555 if (MATCHER_ERROR(rv)) {
556 *status = CMD_ERR_NO_MATCH;
557 return NULL;
558 }
b92938a7 559
d62a17ae 560 vector comps = completions_to_vec(completions);
6a154c88 561 list_delete(&completions);
b92938a7 562
d62a17ae 563 // set status code appropriately
564 switch (vector_active(comps)) {
565 case 0:
566 *status = CMD_ERR_NO_MATCH;
567 break;
568 case 1:
569 *status = CMD_COMPLETE_FULL_MATCH;
570 break;
571 default:
572 *status = CMD_COMPLETE_LIST_MATCH;
573 }
718e3744 574
d62a17ae 575 return comps;
d0bfb22c 576}
718e3744 577
d62a17ae 578vector cmd_describe_command(vector vline, struct vty *vty, int *status)
d0bfb22c 579{
d62a17ae 580 vector ret;
718e3744 581
d62a17ae 582 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
583 enum node_type onode;
1c2facd1 584 int orig_xpath_index;
d62a17ae 585 vector shifted_vline;
586 unsigned int index;
718e3744 587
d62a17ae 588 onode = vty->node;
1c2facd1 589 orig_xpath_index = vty->xpath_index;
d62a17ae 590 vty->node = ENABLE_NODE;
1c2facd1 591 vty->xpath_index = 0;
d62a17ae 592 /* We can try it on enable node, cos' the vty is authenticated
593 */
718e3744 594
d62a17ae 595 shifted_vline = vector_init(vector_count(vline));
596 /* use memcpy? */
597 for (index = 1; index < vector_active(vline); index++) {
598 vector_set_index(shifted_vline, index - 1,
599 vector_lookup(vline, index));
600 }
718e3744 601
d62a17ae 602 ret = cmd_complete_command_real(shifted_vline, vty, status);
d0bfb22c 603
d62a17ae 604 vector_free(shifted_vline);
605 vty->node = onode;
1c2facd1 606 vty->xpath_index = orig_xpath_index;
d62a17ae 607 return ret;
608 }
718e3744 609
d62a17ae 610 return cmd_complete_command_real(vline, vty, status);
718e3744 611}
612
70d44c5c
DL
613static struct list *varhandlers = NULL;
614
d62a17ae 615void cmd_variable_complete(struct cmd_token *token, const char *arg,
616 vector comps)
617{
618 struct listnode *ln;
619 const struct cmd_variable_handler *cvh;
620 size_t i, argsz;
621 vector tmpcomps;
622
623 tmpcomps = arg ? vector_init(VECTOR_MIN_SIZE) : comps;
624
625 for (ALL_LIST_ELEMENTS_RO(varhandlers, ln, cvh)) {
626 if (cvh->tokenname && strcmp(cvh->tokenname, token->text))
627 continue;
9d303b37
DL
628 if (cvh->varname && (!token->varname
629 || strcmp(cvh->varname, token->varname)))
d62a17ae 630 continue;
631 cvh->completions(tmpcomps, token);
632 break;
633 }
634
635 if (!arg)
636 return;
637
638 argsz = strlen(arg);
639 for (i = vector_active(tmpcomps); i; i--) {
640 char *item = vector_slot(tmpcomps, i - 1);
641 if (strlen(item) >= argsz && !strncmp(item, arg, argsz))
642 vector_set(comps, item);
643 else
644 XFREE(MTYPE_COMPLETION, item);
645 }
646 vector_free(tmpcomps);
70d44c5c
DL
647}
648
1a0f614d
QY
649#define AUTOCOMP_INDENT 5
650
d62a17ae 651char *cmd_variable_comp2str(vector comps, unsigned short cols)
1a0f614d 652{
d62a17ae 653 size_t bsz = 16;
654 char *buf = XCALLOC(MTYPE_TMP, bsz);
655 int lc = AUTOCOMP_INDENT;
656 size_t cs = AUTOCOMP_INDENT;
657 size_t itemlen;
658 snprintf(buf, bsz, "%*s", AUTOCOMP_INDENT, "");
659 for (size_t j = 0; j < vector_active(comps); j++) {
660 char *item = vector_slot(comps, j);
661 itemlen = strlen(item);
1a0f614d 662
d62a17ae 663 if (cs + itemlen + AUTOCOMP_INDENT + 3 >= bsz)
664 buf = XREALLOC(MTYPE_TMP, buf, (bsz *= 2));
1a0f614d 665
d62a17ae 666 if (lc + itemlen + 1 >= cols) {
667 cs += snprintf(&buf[cs], bsz - cs, "\n%*s",
668 AUTOCOMP_INDENT, "");
669 lc = AUTOCOMP_INDENT;
670 }
1a0f614d 671
d62a17ae 672 size_t written = snprintf(&buf[cs], bsz - cs, "%s ", item);
673 lc += written;
674 cs += written;
675 XFREE(MTYPE_COMPLETION, item);
676 vector_set_index(comps, j, NULL);
677 }
678 return buf;
1a0f614d
QY
679}
680
d62a17ae 681void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
70d44c5c 682{
d62a17ae 683 if (!varhandlers)
684 return;
70d44c5c 685
d62a17ae 686 for (; cvh->completions; cvh++)
687 listnode_add(varhandlers, (void *)cvh);
70d44c5c
DL
688}
689
7f059ea6
DL
690DEFUN_HIDDEN (autocomplete,
691 autocomplete_cmd,
692 "autocomplete TYPE TEXT VARNAME",
693 "Autocompletion handler (internal, for vtysh)\n"
694 "cmd_token->type\n"
695 "cmd_token->text\n"
696 "cmd_token->varname\n")
697{
d62a17ae 698 struct cmd_token tok;
699 vector comps = vector_init(32);
700 size_t i;
7f059ea6 701
d62a17ae 702 memset(&tok, 0, sizeof(tok));
703 tok.type = atoi(argv[1]->arg);
704 tok.text = argv[2]->arg;
705 tok.varname = argv[3]->arg;
706 if (!strcmp(tok.varname, "-"))
707 tok.varname = NULL;
7f059ea6 708
d62a17ae 709 cmd_variable_complete(&tok, NULL, comps);
7f059ea6 710
d62a17ae 711 for (i = 0; i < vector_active(comps); i++) {
712 char *text = vector_slot(comps, i);
713 vty_out(vty, "%s\n", text);
714 XFREE(MTYPE_COMPLETION, text);
715 }
7f059ea6 716
d62a17ae 717 vector_free(comps);
718 return CMD_SUCCESS;
7f059ea6
DL
719}
720
ebacb4ed
QY
721/**
722 * Generate possible tab-completions for the given input. This function only
723 * returns results that would result in a valid command if used as Readline
724 * completions (as is the case in vtysh). For instance, if the passed vline ends
725 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
726 *
727 * @param vline vectorized input line
728 * @param vty the vty
729 * @param status location to store matcher status code in
730 * @return set of valid strings for use with Readline as tab-completions.
731 */
732
d62a17ae 733char **cmd_complete_command(vector vline, struct vty *vty, int *status)
734{
735 char **ret = NULL;
736 int original_node = vty->node;
737 vector input_line = vector_init(vector_count(vline));
738
739 // if the first token is 'do' we'll want to execute the command in the
740 // enable node
741 int do_shortcut = cmd_try_do_shortcut(vty->node, vector_slot(vline, 0));
742 vty->node = do_shortcut ? ENABLE_NODE : original_node;
743
744 // construct the input line we'll be matching on
745 unsigned int offset = (do_shortcut) ? 1 : 0;
746 for (unsigned index = 0; index + offset < vector_active(vline); index++)
747 vector_set_index(input_line, index,
748 vector_lookup(vline, index + offset));
749
750 // get token completions -- this is a copying operation
751 vector comps = NULL, initial_comps;
752 initial_comps = cmd_complete_command_real(input_line, vty, status);
753
754 if (!MATCHER_ERROR(*status)) {
755 assert(initial_comps);
756 // filter out everything that is not suitable for a
757 // tab-completion
758 comps = vector_init(VECTOR_MIN_SIZE);
759 for (unsigned int i = 0; i < vector_active(initial_comps);
760 i++) {
761 struct cmd_token *token = vector_slot(initial_comps, i);
762 if (token->type == WORD_TKN)
763 vector_set(comps, XSTRDUP(MTYPE_COMPLETION,
764 token->text));
765 else if (IS_VARYING_TOKEN(token->type)) {
766 const char *ref = vector_lookup(
767 vline, vector_active(vline) - 1);
768 cmd_variable_complete(token, ref, comps);
769 }
770 }
771 vector_free(initial_comps);
772
773 // since we filtered results, we need to re-set status code
774 switch (vector_active(comps)) {
775 case 0:
776 *status = CMD_ERR_NO_MATCH;
777 break;
778 case 1:
779 *status = CMD_COMPLETE_FULL_MATCH;
780 break;
781 default:
782 *status = CMD_COMPLETE_LIST_MATCH;
783 }
784
785 // copy completions text into an array of char*
786 ret = XMALLOC(MTYPE_TMP,
787 (vector_active(comps) + 1) * sizeof(char *));
788 unsigned int i;
789 for (i = 0; i < vector_active(comps); i++) {
790 ret[i] = vector_slot(comps, i);
791 }
792 // set the last element to NULL, because this array is used in
793 // a Readline completion_generator function which expects NULL
794 // as a sentinel value
795 ret[i] = NULL;
796 vector_free(comps);
797 comps = NULL;
798 } else if (initial_comps)
799 vector_free(initial_comps);
800
801 // comps should always be null here
802 assert(!comps);
803
804 // free the adjusted input line
805 vector_free(input_line);
806
807 // reset vty->node to its original value
808 vty->node = original_node;
809
810 return ret;
cde9f101 811}
b92938a7 812
b92938a7 813/* return parent node */
814/* MUST eventually converge on CONFIG_NODE */
d62a17ae 815enum node_type node_parent(enum node_type node)
816{
817 enum node_type ret;
818
819 assert(node > CONFIG_NODE);
820
821 switch (node) {
822 case BGP_VPNV4_NODE:
823 case BGP_VPNV6_NODE:
7c40bf39 824 case BGP_FLOWSPECV4_NODE:
825 case BGP_FLOWSPECV6_NODE:
d62a17ae 826 case BGP_VRF_POLICY_NODE:
827 case BGP_VNC_DEFAULTS_NODE:
828 case BGP_VNC_NVE_GROUP_NODE:
829 case BGP_VNC_L2_GROUP_NODE:
830 case BGP_IPV4_NODE:
831 case BGP_IPV4M_NODE:
832 case BGP_IPV4L_NODE:
833 case BGP_IPV6_NODE:
834 case BGP_IPV6M_NODE:
835 case BGP_EVPN_NODE:
836 case BGP_IPV6L_NODE:
ed18356f 837 case BMP_NODE:
d62a17ae 838 ret = BGP_NODE;
839 break;
840 case BGP_EVPN_VNI_NODE:
841 ret = BGP_EVPN_NODE;
842 break;
843 case KEYCHAIN_KEY_NODE:
844 ret = KEYCHAIN_NODE;
845 break;
846 case LINK_PARAMS_NODE:
847 ret = INTERFACE_NODE;
848 break;
849 case LDP_IPV4_NODE:
850 case LDP_IPV6_NODE:
851 ret = LDP_NODE;
852 break;
853 case LDP_IPV4_IFACE_NODE:
854 ret = LDP_IPV4_NODE;
855 break;
856 case LDP_IPV6_IFACE_NODE:
857 ret = LDP_IPV6_NODE;
858 break;
859 case LDP_PSEUDOWIRE_NODE:
860 ret = LDP_L2VPN_NODE;
861 break;
c2f29cf3
RZ
862 case BFD_PEER_NODE:
863 ret = BFD_NODE;
864 break;
d40d6c22
RZ
865 case BFD_PROFILE_NODE:
866 ret = BFD_NODE;
867 break;
4d7b695d
SM
868 case SR_TRAFFIC_ENG_NODE:
869 ret = SEGMENT_ROUTING_NODE;
870 break;
871 case SR_SEGMENT_LIST_NODE:
872 ret = SR_TRAFFIC_ENG_NODE;
873 break;
874 case SR_POLICY_NODE:
875 ret = SR_TRAFFIC_ENG_NODE;
876 break;
877 case SR_CANDIDATE_DYN_NODE:
878 ret = SR_POLICY_NODE;
879 break;
efba0985
SM
880 case PCEP_NODE:
881 ret = SR_TRAFFIC_ENG_NODE;
882 break;
883 case PCEP_PCE_CONFIG_NODE:
884 ret = PCEP_NODE;
885 break;
886 case PCEP_PCE_NODE:
887 ret = PCEP_NODE;
888 break;
889 case PCEP_PCC_NODE:
890 ret = PCEP_NODE;
891 break;
d62a17ae 892 default:
893 ret = CONFIG_NODE;
894 break;
895 }
896
897 return ret;
b92938a7 898}
899
718e3744 900/* Execute command by argument vline vector. */
c139972c 901static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
d62a17ae 902 struct vty *vty,
903 const struct cmd_element **cmd)
904{
905 struct list *argv_list;
906 enum matcher_rv status;
907 const struct cmd_element *matched_element = NULL;
908
909 struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
910 status = command_match(cmdgraph, vline, &argv_list, &matched_element);
911
912 if (cmd)
913 *cmd = matched_element;
914
915 // if matcher error, return corresponding CMD_ERR
916 if (MATCHER_ERROR(status)) {
917 if (argv_list)
6a154c88 918 list_delete(&argv_list);
d62a17ae 919 switch (status) {
920 case MATCHER_INCOMPLETE:
921 return CMD_ERR_INCOMPLETE;
922 case MATCHER_AMBIGUOUS:
923 return CMD_ERR_AMBIGUOUS;
924 default:
925 return CMD_ERR_NO_MATCH;
926 }
927 }
928
929 // build argv array from argv list
930 struct cmd_token **argv = XMALLOC(
931 MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
932 struct listnode *ln;
933 struct cmd_token *token;
934 unsigned int i = 0;
935 for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
936 argv[i++] = token;
937
938 int argc = argv_list->count;
939
940 int ret;
941 if (matched_element->daemon)
942 ret = CMD_SUCCESS_DAEMON;
a6233bfc 943 else {
eaf6705d
RW
944 if (vty->config) {
945 /* Clear array of enqueued configuration changes. */
946 vty->num_cfg_changes = 0;
947 memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
948
689b9cf5
RW
949 /* Regenerate candidate configuration if necessary. */
950 if (frr_get_cli_mode() == FRR_CLI_CLASSIC
951 && running_config->version
952 > vty->candidate_config->version)
eaf6705d
RW
953 nb_config_replace(vty->candidate_config,
954 running_config, true);
b855e95f
RW
955
956 /*
957 * Perform pending commit (if any) before executing
958 * non-YANG command.
959 */
960 if (matched_element->attr != CMD_ATTR_YANG)
961 nb_cli_pending_commit_check(vty);
eaf6705d 962 }
a6233bfc 963
d62a17ae 964 ret = matched_element->func(matched_element, vty, argc, argv);
a6233bfc 965 }
d62a17ae 966
967 // delete list and cmd_token's in it
6a154c88 968 list_delete(&argv_list);
d62a17ae 969 XFREE(MTYPE_TMP, argv);
970
971 return ret;
718e3744 972}
973
cd40b329
CF
974/**
975 * Execute a given command, handling things like "do ..." and checking
976 * whether the given command might apply at a parent node if doesn't
977 * apply for the current node.
978 *
979 * @param vline Command line input, vector of char* where each element is
980 * one input token.
981 * @param vty The vty context in which the command should be executed.
982 * @param cmd Pointer where the struct cmd_element of the matched command
983 * will be stored, if any. May be set to NULL if this info is
984 * not needed.
985 * @param vtysh If set != 0, don't lookup the command at parent nodes.
986 * @return The status of the command that has been executed or an error code
987 * as to why no command could be executed.
988 */
d62a17ae 989int cmd_execute_command(vector vline, struct vty *vty,
990 const struct cmd_element **cmd, int vtysh)
17aca20b 991{
d62a17ae 992 int ret, saved_ret = 0;
993 enum node_type onode, try_node;
1c2facd1 994 int orig_xpath_index;
eda031f6 995
d62a17ae 996 onode = try_node = vty->node;
1c2facd1 997 orig_xpath_index = vty->xpath_index;
b92938a7 998
d62a17ae 999 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1000 vector shifted_vline;
1001 unsigned int index;
b92938a7 1002
d62a17ae 1003 vty->node = ENABLE_NODE;
1c2facd1 1004 vty->xpath_index = 0;
d62a17ae 1005 /* We can try it on enable node, cos' the vty is authenticated
1006 */
b92938a7 1007
d62a17ae 1008 shifted_vline = vector_init(vector_count(vline));
1009 /* use memcpy? */
1010 for (index = 1; index < vector_active(vline); index++)
1011 vector_set_index(shifted_vline, index - 1,
1012 vector_lookup(vline, index));
b92938a7 1013
d62a17ae 1014 ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
1015 vty, cmd);
b92938a7 1016
d62a17ae 1017 vector_free(shifted_vline);
1018 vty->node = onode;
1c2facd1 1019 vty->xpath_index = orig_xpath_index;
d62a17ae 1020 return ret;
1021 }
b92938a7 1022
d62a17ae 1023 saved_ret = ret =
1024 cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
b92938a7 1025
d62a17ae 1026 if (vtysh)
1027 return saved_ret;
87d683b0 1028
825d5fbf
CS
1029 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1030 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
d62a17ae 1031 /* This assumes all nodes above CONFIG_NODE are childs of
1032 * CONFIG_NODE */
1033 while (vty->node > CONFIG_NODE) {
1034 try_node = node_parent(try_node);
1035 vty->node = try_node;
dd90823b
CS
1036 if (vty->xpath_index > 0
1037 && vty_check_node_for_xpath_decrement(try_node,
1038 onode))
1c2facd1 1039 vty->xpath_index--;
d62a17ae 1040 ret = cmd_execute_command_real(vline, FILTER_RELAXED,
1041 vty, cmd);
825d5fbf
CS
1042 if (ret == CMD_SUCCESS || ret == CMD_WARNING
1043 || ret == CMD_NOT_MY_INSTANCE
1044 || ret == CMD_WARNING_CONFIG_FAILED)
d62a17ae 1045 return ret;
1046 }
1047 /* no command succeeded, reset the vty to the original node */
1048 vty->node = onode;
1c2facd1 1049 vty->xpath_index = orig_xpath_index;
d62a17ae 1050 }
04e64062 1051
d62a17ae 1052 /* return command status for original node */
1053 return saved_ret;
b92938a7 1054}
1055
cd40b329
CF
1056/**
1057 * Execute a given command, matching it strictly against the current node.
1058 * This mode is used when reading config files.
1059 *
1060 * @param vline Command line input, vector of char* where each element is
1061 * one input token.
1062 * @param vty The vty context in which the command should be executed.
1063 * @param cmd Pointer where the struct cmd_element* of the matched command
1064 * will be stored, if any. May be set to NULL if this info is
1065 * not needed.
1066 * @return The status of the command that has been executed or an error code
1067 * as to why no command could be executed.
1068 */
d62a17ae 1069int cmd_execute_command_strict(vector vline, struct vty *vty,
1070 const struct cmd_element **cmd)
718e3744 1071{
d62a17ae 1072 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
718e3744 1073}
1074
01e24c4a
QY
1075/*
1076 * Hook for preprocessing command string before executing.
1077 *
1078 * All subscribers are called with the raw command string that is to be
1079 * executed. If any changes are to be made, a new string should be allocated
1080 * with MTYPE_TMP and *cmd_out updated to point to this new string. The caller
1081 * is then responsible for freeing this string.
1082 *
1083 * All processing functions must be mutually exclusive in their action, i.e. if
1084 * one subscriber decides to modify the command, all others must not modify it
1085 * when called. Feeding the output of one processing command into a subsequent
1086 * one is not supported.
1087 *
1088 * This hook is intentionally internal to the command processing system.
1089 *
1090 * cmd_in
1091 * The raw command string.
1092 *
1093 * cmd_out
1094 * The result of any processing.
1095 */
1096DECLARE_HOOK(cmd_execute,
0a334343 1097 (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a 1098 (vty, cmd_in, cmd_out));
0a334343 1099DEFINE_HOOK(cmd_execute, (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a
QY
1100 (vty, cmd_in, cmd_out));
1101
1102/* Hook executed after a CLI command. */
0a334343 1103DECLARE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a 1104 (vty, cmd_exec));
0a334343 1105DEFINE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a
QY
1106 (vty, cmd_exec));
1107
fe6b47b9
QY
1108/*
1109 * cmd_execute hook subscriber to handle `|` actions.
1110 */
1111static int handle_pipe_action(struct vty *vty, const char *cmd_in,
1112 char **cmd_out)
1113{
1114 /* look for `|` */
9f227e4c 1115 char *orig, *working, *token, *u;
fe6b47b9 1116 char *pipe = strstr(cmd_in, "| ");
2f272cb4 1117 int ret = 0;
fe6b47b9
QY
1118
1119 if (!pipe)
1120 return 0;
1121
1122 /* duplicate string for processing purposes, not including pipe */
1123 orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
1124
1125 /* retrieve action */
1126 token = strsep(&working, " ");
4f4060f6 1127 assert(token);
fe6b47b9
QY
1128
1129 /* match result to known actions */
1130 if (strmatch(token, "include")) {
1131 /* the remaining text should be a regexp */
1132 char *regexp = working;
5d806ec6
QY
1133
1134 if (!regexp) {
1135 vty_out(vty, "%% Need a regexp to filter with\n");
2f272cb4 1136 ret = 1;
5d806ec6
QY
1137 goto fail;
1138 }
1139
fe6b47b9 1140 bool succ = vty_set_include(vty, regexp);
0a334343 1141
fe6b47b9 1142 if (!succ) {
5d806ec6 1143 vty_out(vty, "%% Bad regexp '%s'\n", regexp);
2f272cb4 1144 ret = 1;
fe6b47b9
QY
1145 goto fail;
1146 }
2cddf2ff 1147 *cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
9f227e4c 1148 u = *cmd_out;
1149 strsep(&u, "|");
fe6b47b9 1150 } else {
5d806ec6 1151 vty_out(vty, "%% Unknown action '%s'\n", token);
2f272cb4 1152 ret = 1;
fe6b47b9
QY
1153 goto fail;
1154 }
1155
1156fail:
1157 XFREE(MTYPE_TMP, orig);
2f272cb4 1158 return ret;
fe6b47b9
QY
1159}
1160
1161static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
1162{
0b42d81a 1163 if (vty->filter)
fe6b47b9 1164 vty_set_include(vty, NULL);
0b42d81a 1165
fe6b47b9
QY
1166 return 0;
1167}
1168
01e24c4a
QY
1169int cmd_execute(struct vty *vty, const char *cmd,
1170 const struct cmd_element **matched, int vtysh)
1171{
1172 int ret;
1173 char *cmd_out = NULL;
2f272cb4 1174 const char *cmd_exec = NULL;
01e24c4a
QY
1175 vector vline;
1176
2f272cb4
IR
1177 ret = hook_call(cmd_execute, vty, cmd, &cmd_out);
1178 if (ret) {
1179 ret = CMD_WARNING;
1180 goto free;
1181 }
1182
01e24c4a
QY
1183 cmd_exec = cmd_out ? (const char *)cmd_out : cmd;
1184
1185 vline = cmd_make_strvec(cmd_exec);
1186
1187 if (vline) {
1188 ret = cmd_execute_command(vline, vty, matched, vtysh);
1189 cmd_free_strvec(vline);
1190 } else {
1191 ret = CMD_SUCCESS;
1192 }
1193
2f272cb4 1194free:
01e24c4a
QY
1195 hook_call(cmd_execute_done, vty, cmd_exec);
1196
0a22ddfb 1197 XFREE(MTYPE_TMP, cmd_out);
01e24c4a
QY
1198
1199 return ret;
1200}
1201
1202
bed578b8 1203/**
d62a17ae 1204 * Parse one line of config, walking up the parse tree attempting to find a
1205 * match
bed578b8
DS
1206 *
1207 * @param vty The vty context in which the command should be executed.
1208 * @param cmd Pointer where the struct cmd_element* of the match command
1209 * will be stored, if any. May be set to NULL if this info is
1210 * not needed.
d62a17ae 1211 * @param use_daemon Boolean to control whether or not we match on
1212 * CMD_SUCCESS_DAEMON
bed578b8
DS
1213 * or not.
1214 * @return The status of the command that has been executed or an error code
1215 * as to why no command could be executed.
1216 */
d62a17ae 1217int command_config_read_one_line(struct vty *vty,
7ab57d19
DS
1218 const struct cmd_element **cmd,
1219 uint32_t line_num, int use_daemon)
bed578b8 1220{
d62a17ae 1221 vector vline;
d62a17ae 1222 int ret;
bed578b8 1223
d62a17ae 1224 vline = cmd_make_strvec(vty->buf);
bed578b8 1225
d62a17ae 1226 /* In case of comment line */
1227 if (vline == NULL)
1228 return CMD_SUCCESS;
bed578b8 1229
d62a17ae 1230 /* Execute configuration command : this is strict match */
1231 ret = cmd_execute_command_strict(vline, vty, cmd);
bed578b8 1232
d62a17ae 1233 // Climb the tree and try the command again at each node
1234 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1235 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1236 && ret != CMD_SUCCESS && ret != CMD_WARNING
996c9314 1237 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
d62a17ae 1238 && vty->node != CONFIG_NODE) {
1c2facd1
RW
1239 int saved_node = vty->node;
1240 int saved_xpath_index = vty->xpath_index;
bed578b8 1241
d62a17ae 1242 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1243 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1244 && ret != CMD_SUCCESS && ret != CMD_WARNING
1245 && vty->node > CONFIG_NODE) {
1246 vty->node = node_parent(vty->node);
dd90823b
CS
1247 if (vty->xpath_index > 0
1248 && vty_check_node_for_xpath_decrement(vty->node,
1249 saved_node))
1c2facd1 1250 vty->xpath_index--;
d62a17ae 1251 ret = cmd_execute_command_strict(vline, vty, cmd);
1252 }
bed578b8 1253
d62a17ae 1254 // If climbing the tree did not work then ignore the command and
1255 // stay at the same node
1256 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1257 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1258 && ret != CMD_SUCCESS && ret != CMD_WARNING) {
1259 vty->node = saved_node;
1c2facd1 1260 vty->xpath_index = saved_xpath_index;
d62a17ae 1261 }
1262 }
bed578b8 1263
b45d8ccc
DS
1264 if (ret != CMD_SUCCESS &&
1265 ret != CMD_WARNING &&
1266 ret != CMD_SUCCESS_DAEMON) {
7ab57d19
DS
1267 struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve));
1268
1269 memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
1270 ve->line_num = line_num;
1271 if (!vty->error)
1272 vty->error = list_new();
1273
1274 listnode_add(vty->error, ve);
1275 }
cbd7259d 1276
d62a17ae 1277 cmd_free_strvec(vline);
bed578b8 1278
d62a17ae 1279 return ret;
bed578b8
DS
1280}
1281
5689fe5f 1282/* Configuration make from file. */
d62a17ae 1283int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 1284{
d62a17ae 1285 int ret, error_ret = 0;
1286 *line_num = 0;
718e3744 1287
d62a17ae 1288 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
7ab57d19 1289 ++(*line_num);
13fbc82d 1290
7ab57d19 1291 ret = command_config_read_one_line(vty, NULL, *line_num, 0);
718e3744 1292
d62a17ae 1293 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1294 && ret != CMD_ERR_NOTHING_TODO)
1295 error_ret = ret;
1296 }
5689fe5f 1297
d62a17ae 1298 if (error_ret) {
1299 return error_ret;
1300 }
5689fe5f 1301
d62a17ae 1302 return CMD_SUCCESS;
718e3744 1303}
1304
5689fe5f 1305/* Configuration from terminal */
718e3744 1306DEFUN (config_terminal,
1307 config_terminal_cmd,
dc1c13c0 1308 "configure [terminal]",
718e3744 1309 "Configuration from vty interface\n"
1310 "Configuration terminal\n")
1311{
f344c66e 1312 return vty_config_enter(vty, false, false);
718e3744 1313}
1314
1315/* Enable command */
d0bfb22c 1316DEFUN (enable,
718e3744 1317 config_enable_cmd,
1318 "enable",
1319 "Turn on privileged mode command\n")
1320{
d62a17ae 1321 /* If enable password is NULL, change to ENABLE_NODE */
1322 if ((host.enable == NULL && host.enable_encrypt == NULL)
1323 || vty->type == VTY_SHELL_SERV)
1324 vty->node = ENABLE_NODE;
1325 else
1326 vty->node = AUTH_ENABLE_NODE;
718e3744 1327
d62a17ae 1328 return CMD_SUCCESS;
718e3744 1329}
1330
1331/* Disable command */
d0bfb22c 1332DEFUN (disable,
718e3744 1333 config_disable_cmd,
1334 "disable",
1335 "Turn off privileged mode command\n")
1336{
d62a17ae 1337 if (vty->node == ENABLE_NODE)
1338 vty->node = VIEW_NODE;
1339 return CMD_SUCCESS;
718e3744 1340}
1341
1342/* Down vty node level. */
1343DEFUN (config_exit,
1344 config_exit_cmd,
1345 "exit",
1346 "Exit current mode and down to previous mode\n")
0b84f294 1347{
d62a17ae 1348 cmd_exit(vty);
1349 return CMD_SUCCESS;
1350}
1351
791ded4a
DL
1352static int root_on_exit(struct vty *vty)
1353{
1354 if (vty_shell(vty))
1355 exit(0);
1356 else
1357 vty->status = VTY_CLOSE;
1358 return 0;
1359}
1360
d62a17ae 1361void cmd_exit(struct vty *vty)
1362{
24389580 1363 struct cmd_node *cnode = vector_lookup(cmdvec, vty->node);
1c2facd1 1364
791ded4a
DL
1365 if (cnode->node_exit) {
1366 if (!cnode->node_exit(vty))
1367 return;
d62a17ae 1368 }
791ded4a
DL
1369 if (cnode->parent_node)
1370 vty->node = cnode->parent_node;
dd90823b
CS
1371 if (vty->xpath_index > 0
1372 && vty_check_node_for_xpath_decrement(vty->node, cnode->node))
1c2facd1 1373 vty->xpath_index--;
718e3744 1374}
1375
f667a580
QY
1376/* ALIAS_FIXME */
1377DEFUN (config_quit,
1378 config_quit_cmd,
1379 "quit",
1380 "Exit current mode and down to previous mode\n")
1381{
d62a17ae 1382 return config_exit(self, vty, argc, argv);
f667a580
QY
1383}
1384
d0bfb22c 1385
718e3744 1386/* End of configuration. */
1387DEFUN (config_end,
1388 config_end_cmd,
1389 "end",
efd7904e 1390 "End current mode and change to enable mode.\n")
718e3744 1391{
cf09d3ca 1392 if (vty->config) {
f344c66e 1393 vty_config_exit(vty);
d62a17ae 1394 vty->node = ENABLE_NODE;
d62a17ae 1395 }
1396 return CMD_SUCCESS;
718e3744 1397}
1398
1399/* Show version. */
1400DEFUN (show_version,
1401 show_version_cmd,
1402 "show version",
1403 SHOW_STR
1404 "Displays zebra version\n")
1405{
d62a17ae 1406 vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION,
6b3ee3a0 1407 cmd_hostname_get() ? cmd_hostname_get() : "");
d62a17ae 1408 vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
e063f271 1409#ifdef ENABLE_VERSION_BUILD_CONFIG
d62a17ae 1410 vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
e063f271 1411#endif
d62a17ae 1412 return CMD_SUCCESS;
718e3744 1413}
1414
1415/* Help display function for all node. */
1416DEFUN (config_help,
1417 config_help_cmd,
1418 "help",
1419 "Description of the interactive help system\n")
1420{
d62a17ae 1421 vty_out(vty,
1422 "Quagga VTY provides advanced help feature. When you need help,\n\
61b7d449
DL
1423anytime at the command line please press '?'.\n\
1424\n\
1425If nothing matches, the help list will be empty and you must backup\n\
1426 until entering a '?' shows the available options.\n\
1427Two styles of help are provided:\n\
14281. Full help is available when you are ready to enter a\n\
1429command argument (e.g. 'show ?') and describes each possible\n\
1430argument.\n\
14312. Partial help is provided when an abbreviated argument is entered\n\
1432 and you want to know what arguments match the input\n\
1433 (e.g. 'show me?'.)\n\n");
d62a17ae 1434 return CMD_SUCCESS;
1435}
1436
1437static void permute(struct graph_node *start, struct vty *vty)
1438{
1439 static struct list *position = NULL;
1440 if (!position)
1441 position = list_new();
1442
1443 struct cmd_token *stok = start->data;
1444 struct graph_node *gnn;
1445 struct listnode *ln;
1446
1447 // recursive dfs
1448 listnode_add(position, start);
1449 for (unsigned int i = 0; i < vector_active(start->to); i++) {
1450 struct graph_node *gn = vector_slot(start->to, i);
1451 struct cmd_token *tok = gn->data;
1452 if (tok->attr == CMD_ATTR_HIDDEN
1453 || tok->attr == CMD_ATTR_DEPRECATED)
1454 continue;
1455 else if (tok->type == END_TKN || gn == start) {
1456 vty_out(vty, " ");
1457 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
1458 struct cmd_token *tt = gnn->data;
1459 if (tt->type < SPECIAL_TKN)
1460 vty_out(vty, " %s", tt->text);
1461 }
1462 if (gn == start)
1463 vty_out(vty, "...");
1464 vty_out(vty, "\n");
1465 } else {
1466 bool skip = false;
1467 if (stok->type == FORK_TKN && tok->type != FORK_TKN)
1468 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
1469 if (gnn == gn) {
1470 skip = true;
1471 break;
1472 }
1473 if (!skip)
1474 permute(gn, vty);
1475 }
1476 }
1477 list_delete_node(position, listtail(position));
1478}
1479
1480int cmd_list_cmds(struct vty *vty, int do_permute)
1481{
1482 struct cmd_node *node = vector_slot(cmdvec, vty->node);
1483
1484 if (do_permute)
1485 permute(vector_slot(node->cmdgraph->nodes, 0), vty);
1486 else {
1487 /* loop over all commands at this node */
154e9ca1 1488 const struct cmd_element *element = NULL;
d62a17ae 1489 for (unsigned int i = 0; i < vector_active(node->cmd_vector);
1490 i++)
1491 if ((element = vector_slot(node->cmd_vector, i))
1492 && element->attr != CMD_ATTR_DEPRECATED
1493 && element->attr != CMD_ATTR_HIDDEN)
1494 vty_out(vty, " %s\n", element->string);
1495 }
1496 return CMD_SUCCESS;
718e3744 1497}
1498
0b84f294
DL
1499/* Help display function for all node. */
1500DEFUN (config_list,
1501 config_list_cmd,
1502 "list [permutations]",
1503 "Print command list\n"
1504 "Print all possible command permutations\n")
1505{
d62a17ae 1506 return cmd_list_cmds(vty, argc == 2);
0b84f294
DL
1507}
1508
a2454870
QY
1509DEFUN (show_commandtree,
1510 show_commandtree_cmd,
1511 "show commandtree [permutations]",
1512 SHOW_STR
5a1945e4
DS
1513 "Show command tree\n"
1514 "Permutations that we are interested in\n")
a2454870 1515{
d62a17ae 1516 return cmd_list_cmds(vty, argc == 3);
a2454870
QY
1517}
1518
26fbe472
QY
1519DEFUN_HIDDEN(show_cli_graph,
1520 show_cli_graph_cmd,
1521 "show cli graph",
1522 SHOW_STR
1523 "CLI reflection\n"
1524 "Dump current command space as DOT graph\n")
1525{
1526 struct cmd_node *cn = vector_slot(cmdvec, vty->node);
1527 char *dot = cmd_graph_dump_dot(cn->cmdgraph);
1528
1529 vty_out(vty, "%s\n", dot);
1530 XFREE(MTYPE_TMP, dot);
1531 return CMD_SUCCESS;
1532}
1533
f806f29c 1534static int vty_write_config(struct vty *vty)
8efe88ea 1535{
d62a17ae 1536 size_t i;
1537 struct cmd_node *node;
8efe88ea 1538
f806f29c 1539 if (host.noconfig)
1540 return CMD_SUCCESS;
1541
5e6a9350
RW
1542 nb_cli_show_config_prepare(running_config, false);
1543
d62a17ae 1544 if (vty->type == VTY_TERM) {
1545 vty_out(vty, "\nCurrent configuration:\n");
1546 vty_out(vty, "!\n");
1547 }
8efe88ea 1548
ac4adef4
DL
1549 if (strcmp(frr_defaults_version(), FRR_VER_SHORT))
1550 vty_out(vty, "! loaded from %s\n", frr_defaults_version());
d62a17ae 1551 vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
ac4adef4 1552 vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
d62a17ae 1553 vty_out(vty, "!\n");
8efe88ea 1554
8685be73 1555 for (i = 0; i < vector_active(cmdvec); i++)
612c2c15
DL
1556 if ((node = vector_slot(cmdvec, i)) && node->config_write) {
1557 if ((*node->config_write)(vty))
8685be73
RW
1558 vty_out(vty, "!\n");
1559 }
8efe88ea 1560
d62a17ae 1561 if (vty->type == VTY_TERM) {
1562 vty_out(vty, "end\n");
1563 }
8efe88ea 1564
f806f29c 1565 return CMD_SUCCESS;
1566}
d862bffb 1567
f806f29c 1568static int file_write_config(struct vty *vty)
718e3744 1569{
d62a17ae 1570 int fd, dirfd;
1571 char *config_file, *slash;
1572 char *config_file_tmp = NULL;
1573 char *config_file_sav = NULL;
1574 int ret = CMD_WARNING;
1575 struct vty *file_vty;
1576 struct stat conf_stat;
1577
d62a17ae 1578 if (host.noconfig)
1579 return CMD_SUCCESS;
1580
1581 /* Check and see if we are operating under vtysh configuration */
1582 if (host.config == NULL) {
1583 vty_out(vty,
1584 "Can't save to configuration file, using vtysh.\n");
1585 return CMD_WARNING;
1586 }
1587
1588 /* Get filename. */
1589 config_file = host.config;
d0bfb22c 1590
056cfe49
DL
1591#ifndef O_DIRECTORY
1592#define O_DIRECTORY 0
1593#endif
d62a17ae 1594 slash = strrchr(config_file, '/');
1595 if (slash) {
1596 char *config_dir = XSTRDUP(MTYPE_TMP, config_file);
1597 config_dir[slash - config_file] = '\0';
1598 dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
1599 XFREE(MTYPE_TMP, config_dir);
1600 } else
1601 dirfd = open(".", O_DIRECTORY | O_RDONLY);
1602 /* if dirfd is invalid, directory sync fails, but we're still OK */
1603
9f73d2c9
QY
1604 size_t config_file_sav_sz = strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1;
1605 config_file_sav = XMALLOC(MTYPE_TMP, config_file_sav_sz);
1606 strlcpy(config_file_sav, config_file, config_file_sav_sz);
1607 strlcat(config_file_sav, CONF_BACKUP_EXT, config_file_sav_sz);
d62a17ae 1608
1609
1610 config_file_tmp = XMALLOC(MTYPE_TMP, strlen(config_file) + 8);
fc746f1c
QY
1611 snprintf(config_file_tmp, strlen(config_file) + 8, "%s.XXXXXX",
1612 config_file);
d62a17ae 1613
1614 /* Open file to configuration write. */
1615 fd = mkstemp(config_file_tmp);
1616 if (fd < 0) {
1617 vty_out(vty, "Can't open configuration file %s.\n",
1618 config_file_tmp);
1619 goto finished;
1620 }
1621 if (fchmod(fd, CONFIGFILE_MASK) != 0) {
1622 vty_out(vty, "Can't chmod configuration file %s: %s (%d).\n",
1623 config_file_tmp, safe_strerror(errno), errno);
1624 goto finished;
1625 }
1626
1627 /* Make vty for configuration file. */
1628 file_vty = vty_new();
1629 file_vty->wfd = fd;
1630 file_vty->type = VTY_FILE;
1631
1632 /* Config file header print. */
1633 vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! ");
1634 vty_time_print(file_vty, 1);
1635 vty_out(file_vty, "!\n");
1636 vty_write_config(file_vty);
1637 vty_close(file_vty);
1638
1639 if (stat(config_file, &conf_stat) >= 0) {
1640 if (unlink(config_file_sav) != 0)
1641 if (errno != ENOENT) {
1642 vty_out(vty,
1643 "Can't unlink backup configuration file %s.\n",
1644 config_file_sav);
1645 goto finished;
1646 }
1647 if (link(config_file, config_file_sav) != 0) {
1648 vty_out(vty,
1649 "Can't backup old configuration file %s.\n",
1650 config_file_sav);
1651 goto finished;
1652 }
1653 if (dirfd >= 0)
1654 fsync(dirfd);
1655 }
1656 if (rename(config_file_tmp, config_file) != 0) {
1657 vty_out(vty, "Can't save configuration file %s.\n",
1658 config_file);
1659 goto finished;
1660 }
1661 if (dirfd >= 0)
1662 fsync(dirfd);
1663
1664 vty_out(vty, "Configuration saved to %s\n", config_file);
1665 ret = CMD_SUCCESS;
05865c90 1666
1667finished:
d62a17ae 1668 if (ret != CMD_SUCCESS)
1669 unlink(config_file_tmp);
1670 if (dirfd >= 0)
1671 close(dirfd);
1672 XFREE(MTYPE_TMP, config_file_tmp);
1673 XFREE(MTYPE_TMP, config_file_sav);
1674 return ret;
718e3744 1675}
1676
f806f29c 1677/* Write current configuration into file. */
1678
1679DEFUN (config_write,
1680 config_write_cmd,
1681 "write [<file|memory|terminal>]",
1682 "Write running configuration to memory, network, or terminal\n"
1683 "Write to configuration file\n"
1684 "Write configuration currently in memory\n"
1685 "Write configuration to terminal\n")
1686{
1687 const int idx_type = 1;
1688
1689 // if command was 'write terminal' or 'write memory'
1690 if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal"))) {
1691 return vty_write_config(vty);
1692 }
1693
1694 return file_write_config(vty);
1695}
1696
d862bffb
QY
1697/* ALIAS_FIXME for 'write <terminal|memory>' */
1698DEFUN (show_running_config,
1699 show_running_config_cmd,
1700 "show running-config",
1701 SHOW_STR
f806f29c 1702 "running configuration (same as write terminal)\n")
d862bffb 1703{
f806f29c 1704 return vty_write_config(vty);
d862bffb 1705}
718e3744 1706
d862bffb
QY
1707/* ALIAS_FIXME for 'write file' */
1708DEFUN (copy_runningconf_startupconf,
1709 copy_runningconf_startupconf_cmd,
1710 "copy running-config startup-config",
1711 "Copy configuration\n"
1712 "Copy running config to... \n"
f806f29c 1713 "Copy running config to startup config (same as write file/memory)\n")
d862bffb 1714{
f806f29c 1715 return file_write_config(vty);
d862bffb
QY
1716}
1717/** -- **/
718e3744 1718
1719/* Write startup configuration into the terminal. */
1720DEFUN (show_startup_config,
1721 show_startup_config_cmd,
1722 "show startup-config",
1723 SHOW_STR
d0bfb22c 1724 "Contents of startup configuration\n")
718e3744 1725{
d62a17ae 1726 char buf[BUFSIZ];
1727 FILE *confp;
718e3744 1728
d62a17ae 1729 if (host.noconfig)
1730 return CMD_SUCCESS;
1731 if (host.config == NULL)
1732 return CMD_WARNING;
87f44e2f 1733
d62a17ae 1734 confp = fopen(host.config, "r");
1735 if (confp == NULL) {
1736 vty_out(vty, "Can't open configuration file [%s] due to '%s'\n",
1737 host.config, safe_strerror(errno));
1738 return CMD_WARNING;
1739 }
718e3744 1740
d62a17ae 1741 while (fgets(buf, BUFSIZ, confp)) {
1742 char *cp = buf;
718e3744 1743
d62a17ae 1744 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
1745 cp++;
1746 *cp = '\0';
718e3744 1747
d62a17ae 1748 vty_out(vty, "%s\n", buf);
1749 }
718e3744 1750
d62a17ae 1751 fclose(confp);
718e3744 1752
d62a17ae 1753 return CMD_SUCCESS;
718e3744 1754}
1755
6b3ee3a0
MK
1756int cmd_domainname_set(const char *domainname)
1757{
1758 XFREE(MTYPE_HOST, host.domainname);
1759 host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL;
1760 return CMD_SUCCESS;
1761}
1762
1763/* Hostname configuration */
60466a63
QY
1764DEFUN(config_domainname,
1765 domainname_cmd,
1766 "domainname WORD",
1767 "Set system's domain name\n"
1768 "This system's domain name\n")
6b3ee3a0
MK
1769{
1770 struct cmd_token *word = argv[1];
1771
fefa5e0f 1772 if (!isalpha((unsigned char)word->arg[0])) {
6b3ee3a0
MK
1773 vty_out(vty, "Please specify string starting with alphabet\n");
1774 return CMD_WARNING_CONFIG_FAILED;
1775 }
1776
1777 return cmd_domainname_set(word->arg);
1778}
1779
60466a63
QY
1780DEFUN(config_no_domainname,
1781 no_domainname_cmd,
1782 "no domainname [DOMAINNAME]",
1783 NO_STR
1784 "Reset system's domain name\n"
1785 "domain name of this router\n")
6b3ee3a0
MK
1786{
1787 return cmd_domainname_set(NULL);
1788}
1789
d62a17ae 1790int cmd_hostname_set(const char *hostname)
bff9c3e9 1791{
d62a17ae 1792 XFREE(MTYPE_HOST, host.name);
1793 host.name = hostname ? XSTRDUP(MTYPE_HOST, hostname) : NULL;
1794 return CMD_SUCCESS;
bff9c3e9
DL
1795}
1796
718e3744 1797/* Hostname configuration */
d0bfb22c 1798DEFUN (config_hostname,
718e3744 1799 hostname_cmd,
1800 "hostname WORD",
1801 "Set system's network name\n"
1802 "This system's network name\n")
1803{
d62a17ae 1804 struct cmd_token *word = argv[1];
d0bfb22c 1805
fefa5e0f 1806 if (!isalnum((unsigned char)word->arg[0])) {
63e653a2
LK
1807 vty_out(vty,
1808 "Please specify string starting with alphabet or number\n");
1809 return CMD_WARNING_CONFIG_FAILED;
1810 }
1811
1812 /* With reference to RFC 1123 Section 2.1 */
1813 if (strlen(word->arg) > HOSTNAME_LEN) {
1814 vty_out(vty, "Hostname length should be less than %d chars\n",
1815 HOSTNAME_LEN);
d62a17ae 1816 return CMD_WARNING_CONFIG_FAILED;
1817 }
718e3744 1818
d62a17ae 1819 return cmd_hostname_set(word->arg);
718e3744 1820}
1821
d0bfb22c 1822DEFUN (config_no_hostname,
718e3744 1823 no_hostname_cmd,
1824 "no hostname [HOSTNAME]",
1825 NO_STR
1826 "Reset system's network name\n"
1827 "Host name of this router\n")
1828{
d62a17ae 1829 return cmd_hostname_set(NULL);
718e3744 1830}
1831
1832/* VTY interface password set. */
f412b39a
DW
1833DEFUN (config_password,
1834 password_cmd,
98463e0a 1835 "password [(8-8)] WORD",
322e2d5c 1836 "Modify the terminal connection password\n"
718e3744 1837 "Specifies a HIDDEN password will follow\n"
d0bfb22c 1838 "The password string\n")
718e3744 1839{
d62a17ae 1840 int idx_8 = 1;
1841 int idx_word = 2;
1842 if (argc == 3) // '8' was specified
1843 {
1844 if (host.password)
1845 XFREE(MTYPE_HOST, host.password);
1846 host.password = NULL;
1847 if (host.password_encrypt)
1848 XFREE(MTYPE_HOST, host.password_encrypt);
1849 host.password_encrypt =
1850 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
1851 return CMD_SUCCESS;
1852 }
1853
fefa5e0f 1854 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 1855 vty_out(vty,
1856 "Please specify string starting with alphanumeric\n");
1857 return CMD_WARNING_CONFIG_FAILED;
1858 }
1859
1860 if (host.password)
1861 XFREE(MTYPE_HOST, host.password);
1862 host.password = NULL;
1863
1864 if (host.encrypt) {
1865 if (host.password_encrypt)
1866 XFREE(MTYPE_HOST, host.password_encrypt);
1867 host.password_encrypt =
1868 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
1869 } else
1870 host.password = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
1871
1872 return CMD_SUCCESS;
718e3744 1873}
1874
322e2d5c
PM
1875/* VTY interface password delete. */
1876DEFUN (no_config_password,
1877 no_password_cmd,
1878 "no password",
1879 NO_STR
1880 "Modify the terminal connection password\n")
1881{
1882 bool warned = false;
1883
1884 if (host.password) {
eb83f7ce 1885 if (!vty_shell_serv(vty)) {
4911ca9c 1886 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
1887 warned = true;
1888 }
322e2d5c
PM
1889 XFREE(MTYPE_HOST, host.password);
1890 }
1891 host.password = NULL;
1892
1893 if (host.password_encrypt) {
eb83f7ce 1894 if (!warned && !vty_shell_serv(vty))
4911ca9c 1895 vty_out(vty, NO_PASSWD_CMD_WARNING);
322e2d5c
PM
1896 XFREE(MTYPE_HOST, host.password_encrypt);
1897 }
1898 host.password_encrypt = NULL;
1899
1900 return CMD_SUCCESS;
1901}
1902
718e3744 1903/* VTY enable password set. */
f412b39a
DW
1904DEFUN (config_enable_password,
1905 enable_password_cmd,
98463e0a 1906 "enable password [(8-8)] WORD",
718e3744 1907 "Modify enable password parameters\n"
1908 "Assign the privileged level password\n"
1909 "Specifies a HIDDEN password will follow\n"
718e3744 1910 "The HIDDEN 'enable' password string\n")
1911{
d62a17ae 1912 int idx_8 = 2;
1913 int idx_word = 3;
1914
1915 /* Crypt type is specified. */
1916 if (argc == 4) {
1917 if (argv[idx_8]->arg[0] == '8') {
1918 if (host.enable)
1919 XFREE(MTYPE_HOST, host.enable);
1920 host.enable = NULL;
1921
1922 if (host.enable_encrypt)
1923 XFREE(MTYPE_HOST, host.enable_encrypt);
1924 host.enable_encrypt =
1925 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
1926
1927 return CMD_SUCCESS;
1928 } else {
1929 vty_out(vty, "Unknown encryption type.\n");
1930 return CMD_WARNING_CONFIG_FAILED;
1931 }
1932 }
1933
fefa5e0f 1934 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 1935 vty_out(vty,
1936 "Please specify string starting with alphanumeric\n");
1937 return CMD_WARNING_CONFIG_FAILED;
1938 }
1939
1940 if (host.enable)
1941 XFREE(MTYPE_HOST, host.enable);
1942 host.enable = NULL;
1943
1944 /* Plain password input. */
1945 if (host.encrypt) {
1946 if (host.enable_encrypt)
1947 XFREE(MTYPE_HOST, host.enable_encrypt);
1948 host.enable_encrypt =
1949 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
1950 } else
1951 host.enable = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
1952
1953 return CMD_SUCCESS;
718e3744 1954}
1955
718e3744 1956/* VTY enable password delete. */
f412b39a
DW
1957DEFUN (no_config_enable_password,
1958 no_enable_password_cmd,
718e3744 1959 "no enable password",
1960 NO_STR
1961 "Modify enable password parameters\n"
1962 "Assign the privileged level password\n")
1963{
322e2d5c
PM
1964 bool warned = false;
1965
1966 if (host.enable) {
eb83f7ce 1967 if (!vty_shell_serv(vty)) {
4911ca9c 1968 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
1969 warned = true;
1970 }
d62a17ae 1971 XFREE(MTYPE_HOST, host.enable);
322e2d5c 1972 }
d62a17ae 1973 host.enable = NULL;
718e3744 1974
322e2d5c 1975 if (host.enable_encrypt) {
eb83f7ce 1976 if (!warned && !vty_shell_serv(vty))
4911ca9c 1977 vty_out(vty, NO_PASSWD_CMD_WARNING);
d62a17ae 1978 XFREE(MTYPE_HOST, host.enable_encrypt);
322e2d5c 1979 }
d62a17ae 1980 host.enable_encrypt = NULL;
718e3744 1981
d62a17ae 1982 return CMD_SUCCESS;
718e3744 1983}
d0bfb22c 1984
718e3744 1985DEFUN (service_password_encrypt,
1986 service_password_encrypt_cmd,
1987 "service password-encryption",
1988 "Set up miscellaneous service\n"
1989 "Enable encrypted passwords\n")
1990{
d62a17ae 1991 if (host.encrypt)
1992 return CMD_SUCCESS;
718e3744 1993
d62a17ae 1994 host.encrypt = 1;
718e3744 1995
d62a17ae 1996 if (host.password) {
1997 if (host.password_encrypt)
1998 XFREE(MTYPE_HOST, host.password_encrypt);
1999 host.password_encrypt =
2000 XSTRDUP(MTYPE_HOST, zencrypt(host.password));
2001 }
2002 if (host.enable) {
2003 if (host.enable_encrypt)
2004 XFREE(MTYPE_HOST, host.enable_encrypt);
2005 host.enable_encrypt =
2006 XSTRDUP(MTYPE_HOST, zencrypt(host.enable));
2007 }
718e3744 2008
d62a17ae 2009 return CMD_SUCCESS;
718e3744 2010}
2011
2012DEFUN (no_service_password_encrypt,
2013 no_service_password_encrypt_cmd,
2014 "no service password-encryption",
2015 NO_STR
2016 "Set up miscellaneous service\n"
2017 "Enable encrypted passwords\n")
2018{
d62a17ae 2019 if (!host.encrypt)
2020 return CMD_SUCCESS;
718e3744 2021
d62a17ae 2022 host.encrypt = 0;
718e3744 2023
d62a17ae 2024 if (host.password_encrypt)
2025 XFREE(MTYPE_HOST, host.password_encrypt);
2026 host.password_encrypt = NULL;
718e3744 2027
d62a17ae 2028 if (host.enable_encrypt)
2029 XFREE(MTYPE_HOST, host.enable_encrypt);
2030 host.enable_encrypt = NULL;
718e3744 2031
d62a17ae 2032 return CMD_SUCCESS;
718e3744 2033}
2034
f412b39a
DW
2035DEFUN (config_terminal_length,
2036 config_terminal_length_cmd,
d0bfb22c 2037 "terminal length (0-512)",
718e3744 2038 "Set terminal line parameters\n"
2039 "Set number of lines on a screen\n"
2040 "Number of lines on screen (0 for no pausing)\n")
2041{
d62a17ae 2042 int idx_number = 2;
718e3744 2043
d62a17ae 2044 vty->lines = atoi(argv[idx_number]->arg);
718e3744 2045
d62a17ae 2046 return CMD_SUCCESS;
718e3744 2047}
2048
f412b39a
DW
2049DEFUN (config_terminal_no_length,
2050 config_terminal_no_length_cmd,
718e3744 2051 "terminal no length",
2052 "Set terminal line parameters\n"
2053 NO_STR
2054 "Set number of lines on a screen\n")
2055{
d62a17ae 2056 vty->lines = -1;
2057 return CMD_SUCCESS;
718e3744 2058}
2059
f412b39a
DW
2060DEFUN (service_terminal_length,
2061 service_terminal_length_cmd,
d0bfb22c 2062 "service terminal-length (0-512)",
718e3744 2063 "Set up miscellaneous service\n"
2064 "System wide terminal length configuration\n"
2065 "Number of lines of VTY (0 means no line control)\n")
2066{
d62a17ae 2067 int idx_number = 2;
718e3744 2068
d62a17ae 2069 host.lines = atoi(argv[idx_number]->arg);
718e3744 2070
d62a17ae 2071 return CMD_SUCCESS;
718e3744 2072}
2073
f412b39a
DW
2074DEFUN (no_service_terminal_length,
2075 no_service_terminal_length_cmd,
d0bfb22c 2076 "no service terminal-length [(0-512)]",
718e3744 2077 NO_STR
2078 "Set up miscellaneous service\n"
2079 "System wide terminal length configuration\n"
2080 "Number of lines of VTY (0 means no line control)\n")
2081{
d62a17ae 2082 host.lines = -1;
2083 return CMD_SUCCESS;
718e3744 2084}
2085
2885f72d 2086DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
2087 echo_cmd,
2088 "echo MESSAGE...",
2089 "Echo a message back to the vty\n"
2090 "The message to echo\n")
2885f72d 2091{
d62a17ae 2092 char *message;
2885f72d 2093
d62a17ae 2094 vty_out(vty, "%s\n",
2095 ((message = argv_concat(argv, argc, 1)) ? message : ""));
2096 if (message)
2097 XFREE(MTYPE_TMP, message);
2098 return CMD_SUCCESS;
2885f72d 2099}
2100
274a4a44 2101DEFUN (config_logmsg,
2102 config_logmsg_cmd,
199d90a1 2103 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 2104 "Send a message to enabled logging destinations\n"
2105 LOG_LEVEL_DESC
2106 "The message to send\n")
2107{
d62a17ae 2108 int idx_log_level = 1;
2109 int idx_message = 2;
2110 int level;
2111 char *message;
274a4a44 2112
0bdeb5e5
DL
2113 level = log_level_match(argv[idx_log_level]->arg);
2114 if (level == ZLOG_DISABLED)
d62a17ae 2115 return CMD_ERR_NO_MATCH;
274a4a44 2116
d62a17ae 2117 zlog(level, "%s",
2118 ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
2119 if (message)
2120 XFREE(MTYPE_TMP, message);
65efcfce 2121
d62a17ae 2122 return CMD_SUCCESS;
274a4a44 2123}
2124
9eed278b
DL
2125DEFUN (debug_memstats,
2126 debug_memstats_cmd,
2127 "[no] debug memstats-at-exit",
2128 NO_STR
2129 DEBUG_STR
2130 "Print memory type statistics at exit\n")
2131{
2132 debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
2133 return CMD_SUCCESS;
2134}
2135
d62a17ae 2136int cmd_banner_motd_file(const char *file)
7cfc61d3 2137{
d62a17ae 2138 int success = CMD_SUCCESS;
2139 char p[PATH_MAX];
2140 char *rpath;
2141 char *in;
7cfc61d3 2142
d62a17ae 2143 rpath = realpath(file, p);
2144 if (!rpath)
2145 return CMD_ERR_NO_FILE;
2146 in = strstr(rpath, SYSCONFDIR);
2147 if (in == rpath) {
0a22ddfb 2148 XFREE(MTYPE_HOST, host.motdfile);
d62a17ae 2149 host.motdfile = XSTRDUP(MTYPE_HOST, file);
2150 } else
2151 success = CMD_WARNING_CONFIG_FAILED;
1ee08155 2152
d62a17ae 2153 return success;
7cfc61d3
DS
2154}
2155
19d61463
DA
2156void cmd_banner_motd_line(const char *line)
2157{
e1b36e13 2158 XFREE(MTYPE_HOST, host.motd);
19d61463
DA
2159 host.motd = XSTRDUP(MTYPE_HOST, line);
2160}
2161
3b0c5d9a 2162DEFUN (banner_motd_file,
2163 banner_motd_file_cmd,
4d833e55 2164 "banner motd file FILE",
3b0c5d9a 2165 "Set banner\n"
2166 "Banner for motd\n"
2167 "Banner from a file\n"
2168 "Filename\n")
2169{
d62a17ae 2170 int idx_file = 3;
2171 const char *filename = argv[idx_file]->arg;
2172 int cmd = cmd_banner_motd_file(filename);
1ee08155 2173
d62a17ae 2174 if (cmd == CMD_ERR_NO_FILE)
2175 vty_out(vty, "%s does not exist", filename);
2176 else if (cmd == CMD_WARNING_CONFIG_FAILED)
2177 vty_out(vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155 2178
d62a17ae 2179 return cmd;
3b0c5d9a 2180}
718e3744 2181
19d61463
DA
2182DEFUN (banner_motd_line,
2183 banner_motd_line_cmd,
2184 "banner motd line LINE...",
2185 "Set banner\n"
2186 "Banner for motd\n"
2187 "Banner from an input\n"
2188 "Text\n")
2189{
2190 int idx = 0;
2191 char *motd;
2192
2193 argv_find(argv, argc, "LINE", &idx);
2194 motd = argv_concat(argv, argc, idx);
2195
2196 cmd_banner_motd_line(motd);
2197 XFREE(MTYPE_TMP, motd);
2198
2199 return CMD_SUCCESS;
2200}
2201
718e3744 2202DEFUN (banner_motd_default,
2203 banner_motd_default_cmd,
2204 "banner motd default",
2205 "Set banner string\n"
2206 "Strings for motd\n"
2207 "Default string\n")
2208{
19d61463 2209 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2210 return CMD_SUCCESS;
718e3744 2211}
2212
2213DEFUN (no_banner_motd,
2214 no_banner_motd_cmd,
2215 "no banner motd",
2216 NO_STR
2217 "Set banner string\n"
2218 "Strings for motd\n")
2219{
d62a17ae 2220 host.motd = NULL;
2221 if (host.motdfile)
2222 XFREE(MTYPE_HOST, host.motdfile);
2223 host.motdfile = NULL;
2224 return CMD_SUCCESS;
718e3744 2225}
2226
a83a5331
QY
2227DEFUN(find,
2228 find_cmd,
767f67a4 2229 "find REGEX...",
68912a20
QY
2230 "Find CLI command matching a regular expression\n"
2231 "Search pattern (POSIX regex)\n")
a83a5331 2232{
cf6c83e7
QY
2233 const struct cmd_node *node;
2234 const struct cmd_element *cli;
2235 vector clis;
a83a5331 2236
68912a20
QY
2237 regex_t exp = {};
2238
767f67a4 2239 char *pattern = argv_concat(argv, argc, 1);
68912a20 2240 int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
767f67a4 2241 XFREE(MTYPE_TMP, pattern);
68912a20
QY
2242
2243 if (cr != 0) {
2244 switch (cr) {
2245 case REG_BADBR:
2246 vty_out(vty, "%% Invalid {...} expression\n");
2247 break;
2248 case REG_BADRPT:
2249 vty_out(vty, "%% Bad repetition operator\n");
2250 break;
2251 case REG_BADPAT:
2252 vty_out(vty, "%% Regex syntax error\n");
2253 break;
2254 case REG_ECOLLATE:
2255 vty_out(vty, "%% Invalid collating element\n");
2256 break;
2257 case REG_ECTYPE:
2258 vty_out(vty, "%% Invalid character class name\n");
2259 break;
2260 case REG_EESCAPE:
2261 vty_out(vty,
2262 "%% Regex ended with escape character (\\)\n");
2263 break;
2264 case REG_ESUBREG:
2265 vty_out(vty,
2266 "%% Invalid number in \\digit construction\n");
2267 break;
2268 case REG_EBRACK:
2269 vty_out(vty, "%% Unbalanced square brackets\n");
2270 break;
2271 case REG_EPAREN:
2272 vty_out(vty, "%% Unbalanced parentheses\n");
2273 break;
2274 case REG_EBRACE:
2275 vty_out(vty, "%% Unbalanced braces\n");
2276 break;
2277 case REG_ERANGE:
2278 vty_out(vty,
2279 "%% Invalid endpoint in range expression\n");
2280 break;
2281 case REG_ESPACE:
2282 vty_out(vty, "%% Failed to compile (out of memory)\n");
2283 break;
2284 }
2285
2286 goto done;
2287 }
2288
2289
a83a5331 2290 for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
cf6c83e7 2291 node = vector_slot(cmdvec, i);
a83a5331
QY
2292 if (!node)
2293 continue;
cf6c83e7 2294 clis = node->cmd_vector;
a83a5331 2295 for (unsigned int j = 0; j < vector_active(clis); j++) {
cf6c83e7 2296 cli = vector_slot(clis, j);
68912a20
QY
2297
2298 if (regexec(&exp, cli->string, 0, NULL, 0) == 0)
cf6c83e7 2299 vty_out(vty, " (%s) %s\n",
f4b8291f 2300 node->name, cli->string);
a83a5331
QY
2301 }
2302 }
2303
68912a20
QY
2304done:
2305 regfree(&exp);
a83a5331
QY
2306 return CMD_SUCCESS;
2307}
2308
fa22080d 2309#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
5f98c815
QY
2310DEFUN(script,
2311 script_cmd,
2312 "script SCRIPT",
2313 "Test command - execute a script\n"
2314 "Script name (same as filename in /etc/frr/scripts/\n")
2315{
3d19ffc5 2316 struct prefix p;
45e56ec4
DS
2317
2318 (void)str2prefix("1.2.3.4/24", &p);
3d19ffc5
QY
2319
2320 struct frrscript *fs = frrscript_load(argv[1]->arg, NULL);
5f98c815 2321
3d19ffc5
QY
2322 if (fs == NULL) {
2323 vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n",
2324 argv[1]->arg);
2325 } else {
f869ab17 2326 int ret = frrscript_call(fs, NULL);
3d19ffc5
QY
2327 vty_out(vty, "Script result: %d\n", ret);
2328 }
5f98c815
QY
2329
2330 return CMD_SUCCESS;
2331}
2332#endif
2333
718e3744 2334/* Set config filename. Called from vty.c */
d62a17ae 2335void host_config_set(const char *filename)
718e3744 2336{
0a22ddfb 2337 XFREE(MTYPE_HOST, host.config);
d62a17ae 2338 host.config = XSTRDUP(MTYPE_HOST, filename);
718e3744 2339}
2340
d62a17ae 2341const char *host_config_get(void)
57387fb2 2342{
d62a17ae 2343 return host.config;
57387fb2
CF
2344}
2345
d62a17ae 2346void install_default(enum node_type node)
718e3744 2347{
01485adb
DL
2348 _install_element(node, &config_exit_cmd);
2349 _install_element(node, &config_quit_cmd);
2350 _install_element(node, &config_end_cmd);
2351 _install_element(node, &config_help_cmd);
2352 _install_element(node, &config_list_cmd);
2353 _install_element(node, &show_cli_graph_cmd);
2354 _install_element(node, &find_cmd);
718e3744 2355
01485adb
DL
2356 _install_element(node, &config_write_cmd);
2357 _install_element(node, &show_running_config_cmd);
7f059ea6 2358
01485adb 2359 _install_element(node, &autocomplete_cmd);
1c2facd1
RW
2360
2361 nb_cli_install_default(node);
718e3744 2362}
2363
87f44e2f
DL
2364/* Initialize command interface. Install basic nodes and commands.
2365 *
2366 * terminal = 0 -- vtysh / no logging, no config control
2367 * terminal = 1 -- normal daemon
9473e340 2368 * terminal = -1 -- watchfrr / no logging, but minimal config control */
d62a17ae 2369void cmd_init(int terminal)
2370{
419cd5a0
MK
2371 struct utsname names;
2372
419cd5a0 2373 uname(&names);
d62a17ae 2374 qobj_init();
2375
fe6b47b9
QY
2376 /* register command preprocessors */
2377 hook_register(cmd_execute, handle_pipe_action);
2378 hook_register(cmd_execute_done, handle_pipe_action_done);
2379
d62a17ae 2380 varhandlers = list_new();
2381
2382 /* Allocate initial top vector of commands. */
2383 cmdvec = vector_init(VECTOR_MIN_SIZE);
2384
2385 /* Default host value settings. */
419cd5a0
MK
2386 host.name = XSTRDUP(MTYPE_HOST, names.nodename);
2387#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
6b3ee3a0
MK
2388 if ((strcmp(names.domainname, "(none)") == 0))
2389 host.domainname = NULL;
2390 else
2391 host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
419cd5a0
MK
2392#else
2393 host.domainname = NULL;
2394#endif
d62a17ae 2395 host.password = NULL;
2396 host.enable = NULL;
d62a17ae 2397 host.config = NULL;
2398 host.noconfig = (terminal < 0);
2399 host.lines = -1;
19d61463 2400 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2401 host.motdfile = NULL;
2402
2403 /* Install top nodes. */
612c2c15
DL
2404 install_node(&view_node);
2405 install_node(&enable_node);
2406 install_node(&auth_node);
2407 install_node(&auth_enable_node);
2408 install_node(&config_node);
d62a17ae 2409
2410 /* Each node's basic commands. */
2411 install_element(VIEW_NODE, &show_version_cmd);
a83a5331
QY
2412 install_element(ENABLE_NODE, &show_startup_config_cmd);
2413
d62a17ae 2414 if (terminal) {
85a6806d
MS
2415 install_element(ENABLE_NODE, &debug_memstats_cmd);
2416
d62a17ae 2417 install_element(VIEW_NODE, &config_list_cmd);
2418 install_element(VIEW_NODE, &config_exit_cmd);
2419 install_element(VIEW_NODE, &config_quit_cmd);
2420 install_element(VIEW_NODE, &config_help_cmd);
2421 install_element(VIEW_NODE, &config_enable_cmd);
2422 install_element(VIEW_NODE, &config_terminal_length_cmd);
2423 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
d62a17ae 2424 install_element(VIEW_NODE, &show_commandtree_cmd);
2425 install_element(VIEW_NODE, &echo_cmd);
2426 install_element(VIEW_NODE, &autocomplete_cmd);
a83a5331 2427 install_element(VIEW_NODE, &find_cmd);
fa22080d 2428#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
3d19ffc5
QY
2429 install_element(VIEW_NODE, &script_cmd);
2430#endif
2431
d62a17ae 2432
d62a17ae 2433 install_element(ENABLE_NODE, &config_end_cmd);
2434 install_element(ENABLE_NODE, &config_disable_cmd);
2435 install_element(ENABLE_NODE, &config_terminal_cmd);
2436 install_element(ENABLE_NODE, &copy_runningconf_startupconf_cmd);
2437 install_element(ENABLE_NODE, &config_write_cmd);
2438 install_element(ENABLE_NODE, &show_running_config_cmd);
d62a17ae 2439 install_element(ENABLE_NODE, &config_logmsg_cmd);
a83a5331 2440
d62a17ae 2441 install_default(CONFIG_NODE);
2442
2443 thread_cmd_init();
2444 workqueue_cmd_init();
2445 hash_cmd_init();
2446 }
2447
2448 install_element(CONFIG_NODE, &hostname_cmd);
2449 install_element(CONFIG_NODE, &no_hostname_cmd);
6b3ee3a0
MK
2450 install_element(CONFIG_NODE, &domainname_cmd);
2451 install_element(CONFIG_NODE, &no_domainname_cmd);
d62a17ae 2452
2453 if (terminal > 0) {
0bdeb5e5
DL
2454 full_cli = true;
2455
85a6806d
MS
2456 install_element(CONFIG_NODE, &debug_memstats_cmd);
2457
d62a17ae 2458 install_element(CONFIG_NODE, &password_cmd);
322e2d5c 2459 install_element(CONFIG_NODE, &no_password_cmd);
d62a17ae 2460 install_element(CONFIG_NODE, &enable_password_cmd);
2461 install_element(CONFIG_NODE, &no_enable_password_cmd);
2462
d62a17ae 2463 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
2464 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
2465 install_element(CONFIG_NODE, &banner_motd_default_cmd);
2466 install_element(CONFIG_NODE, &banner_motd_file_cmd);
19d61463 2467 install_element(CONFIG_NODE, &banner_motd_line_cmd);
d62a17ae 2468 install_element(CONFIG_NODE, &no_banner_motd_cmd);
2469 install_element(CONFIG_NODE, &service_terminal_length_cmd);
2470 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
2471
0bdeb5e5 2472 log_cmd_init();
d62a17ae 2473 vrf_install_commands();
2474 }
af2567b6
DL
2475
2476#ifdef DEV_BUILD
d62a17ae 2477 grammar_sandbox_init();
af2567b6 2478#endif
718e3744 2479}
228da428 2480
4d762f26 2481void cmd_terminate(void)
d62a17ae 2482{
2483 struct cmd_node *cmd_node;
2484
5d806ec6
QY
2485 hook_unregister(cmd_execute, handle_pipe_action);
2486 hook_unregister(cmd_execute_done, handle_pipe_action_done);
2487
d62a17ae 2488 if (cmdvec) {
2489 for (unsigned int i = 0; i < vector_active(cmdvec); i++)
2490 if ((cmd_node = vector_slot(cmdvec, i)) != NULL) {
2491 // deleting the graph delets the cmd_element as
2492 // well
2493 graph_delete_graph(cmd_node->cmdgraph);
2494 vector_free(cmd_node->cmd_vector);
2495 hash_clean(cmd_node->cmd_hash, NULL);
2496 hash_free(cmd_node->cmd_hash);
2497 cmd_node->cmd_hash = NULL;
2498 }
2499
2500 vector_free(cmdvec);
2501 cmdvec = NULL;
2502 }
2503
0a22ddfb
QY
2504 XFREE(MTYPE_HOST, host.name);
2505 XFREE(MTYPE_HOST, host.domainname);
2506 XFREE(MTYPE_HOST, host.password);
2507 XFREE(MTYPE_HOST, host.password_encrypt);
2508 XFREE(MTYPE_HOST, host.enable);
2509 XFREE(MTYPE_HOST, host.enable_encrypt);
0a22ddfb
QY
2510 XFREE(MTYPE_HOST, host.motdfile);
2511 XFREE(MTYPE_HOST, host.config);
19d61463 2512 XFREE(MTYPE_HOST, host.motd);
d62a17ae 2513
6a154c88 2514 list_delete(&varhandlers);
d62a17ae 2515 qobj_finish();
228da428 2516}