]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
Merge pull request #8531 from mjstapp/fix_backups_misc
[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,
e3476061
DL
903 const struct cmd_element **cmd,
904 unsigned int up_level)
d62a17ae 905{
906 struct list *argv_list;
907 enum matcher_rv status;
908 const struct cmd_element *matched_element = NULL;
e3476061
DL
909 unsigned int i;
910 int xpath_index = vty->xpath_index;
911 int node = vty->node;
d62a17ae 912
e3476061
DL
913 /* only happens for legacy split config file load; need to check for
914 * a match before calling node_exit handlers below
915 */
916 for (i = 0; i < up_level; i++) {
917 if (node <= CONFIG_NODE)
918 return CMD_NO_LEVEL_UP;
919
920 node = node_parent(node);
921
922 if (xpath_index > 0
923 && vty_check_node_for_xpath_decrement(node, vty->node))
924 xpath_index--;
925 }
926
927 struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
d62a17ae 928 status = command_match(cmdgraph, vline, &argv_list, &matched_element);
929
930 if (cmd)
931 *cmd = matched_element;
932
933 // if matcher error, return corresponding CMD_ERR
934 if (MATCHER_ERROR(status)) {
935 if (argv_list)
6a154c88 936 list_delete(&argv_list);
d62a17ae 937 switch (status) {
938 case MATCHER_INCOMPLETE:
939 return CMD_ERR_INCOMPLETE;
940 case MATCHER_AMBIGUOUS:
941 return CMD_ERR_AMBIGUOUS;
942 default:
943 return CMD_ERR_NO_MATCH;
944 }
945 }
946
e3476061
DL
947 for (i = 0; i < up_level; i++)
948 cmd_exit(vty);
949
d62a17ae 950 // build argv array from argv list
951 struct cmd_token **argv = XMALLOC(
952 MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
953 struct listnode *ln;
954 struct cmd_token *token;
e3476061
DL
955
956 i = 0;
d62a17ae 957 for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
958 argv[i++] = token;
959
960 int argc = argv_list->count;
961
962 int ret;
963 if (matched_element->daemon)
964 ret = CMD_SUCCESS_DAEMON;
a6233bfc 965 else {
eaf6705d
RW
966 if (vty->config) {
967 /* Clear array of enqueued configuration changes. */
968 vty->num_cfg_changes = 0;
969 memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
970
689b9cf5
RW
971 /* Regenerate candidate configuration if necessary. */
972 if (frr_get_cli_mode() == FRR_CLI_CLASSIC
973 && running_config->version
974 > vty->candidate_config->version)
eaf6705d
RW
975 nb_config_replace(vty->candidate_config,
976 running_config, true);
b855e95f
RW
977
978 /*
979 * Perform pending commit (if any) before executing
980 * non-YANG command.
981 */
982 if (matched_element->attr != CMD_ATTR_YANG)
983 nb_cli_pending_commit_check(vty);
eaf6705d 984 }
a6233bfc 985
d62a17ae 986 ret = matched_element->func(matched_element, vty, argc, argv);
a6233bfc 987 }
d62a17ae 988
989 // delete list and cmd_token's in it
6a154c88 990 list_delete(&argv_list);
d62a17ae 991 XFREE(MTYPE_TMP, argv);
992
993 return ret;
718e3744 994}
995
cd40b329
CF
996/**
997 * Execute a given command, handling things like "do ..." and checking
998 * whether the given command might apply at a parent node if doesn't
999 * apply for the current node.
1000 *
1001 * @param vline Command line input, vector of char* where each element is
1002 * one input token.
1003 * @param vty The vty context in which the command should be executed.
1004 * @param cmd Pointer where the struct cmd_element of the matched command
1005 * will be stored, if any. May be set to NULL if this info is
1006 * not needed.
1007 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1008 * @return The status of the command that has been executed or an error code
1009 * as to why no command could be executed.
1010 */
d62a17ae 1011int cmd_execute_command(vector vline, struct vty *vty,
1012 const struct cmd_element **cmd, int vtysh)
17aca20b 1013{
d62a17ae 1014 int ret, saved_ret = 0;
1015 enum node_type onode, try_node;
1c2facd1 1016 int orig_xpath_index;
eda031f6 1017
d62a17ae 1018 onode = try_node = vty->node;
1c2facd1 1019 orig_xpath_index = vty->xpath_index;
b92938a7 1020
d62a17ae 1021 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1022 vector shifted_vline;
1023 unsigned int index;
b92938a7 1024
d62a17ae 1025 vty->node = ENABLE_NODE;
1c2facd1 1026 vty->xpath_index = 0;
d62a17ae 1027 /* We can try it on enable node, cos' the vty is authenticated
1028 */
b92938a7 1029
d62a17ae 1030 shifted_vline = vector_init(vector_count(vline));
1031 /* use memcpy? */
1032 for (index = 1; index < vector_active(vline); index++)
1033 vector_set_index(shifted_vline, index - 1,
1034 vector_lookup(vline, index));
b92938a7 1035
d62a17ae 1036 ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
e3476061 1037 vty, cmd, 0);
b92938a7 1038
d62a17ae 1039 vector_free(shifted_vline);
1040 vty->node = onode;
1c2facd1 1041 vty->xpath_index = orig_xpath_index;
d62a17ae 1042 return ret;
1043 }
b92938a7 1044
d62a17ae 1045 saved_ret = ret =
e3476061 1046 cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
b92938a7 1047
d62a17ae 1048 if (vtysh)
1049 return saved_ret;
87d683b0 1050
825d5fbf
CS
1051 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1052 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
d62a17ae 1053 /* This assumes all nodes above CONFIG_NODE are childs of
1054 * CONFIG_NODE */
1055 while (vty->node > CONFIG_NODE) {
1056 try_node = node_parent(try_node);
1057 vty->node = try_node;
dd90823b
CS
1058 if (vty->xpath_index > 0
1059 && vty_check_node_for_xpath_decrement(try_node,
1060 onode))
1c2facd1 1061 vty->xpath_index--;
d62a17ae 1062 ret = cmd_execute_command_real(vline, FILTER_RELAXED,
e3476061 1063 vty, cmd, 0);
825d5fbf
CS
1064 if (ret == CMD_SUCCESS || ret == CMD_WARNING
1065 || ret == CMD_NOT_MY_INSTANCE
1066 || ret == CMD_WARNING_CONFIG_FAILED)
d62a17ae 1067 return ret;
1068 }
1069 /* no command succeeded, reset the vty to the original node */
1070 vty->node = onode;
1c2facd1 1071 vty->xpath_index = orig_xpath_index;
d62a17ae 1072 }
04e64062 1073
d62a17ae 1074 /* return command status for original node */
1075 return saved_ret;
b92938a7 1076}
1077
cd40b329
CF
1078/**
1079 * Execute a given command, matching it strictly against the current node.
1080 * This mode is used when reading config files.
1081 *
1082 * @param vline Command line input, vector of char* where each element is
1083 * one input token.
1084 * @param vty The vty context in which the command should be executed.
1085 * @param cmd Pointer where the struct cmd_element* of the matched command
1086 * will be stored, if any. May be set to NULL if this info is
1087 * not needed.
1088 * @return The status of the command that has been executed or an error code
1089 * as to why no command could be executed.
1090 */
d62a17ae 1091int cmd_execute_command_strict(vector vline, struct vty *vty,
1092 const struct cmd_element **cmd)
718e3744 1093{
e3476061 1094 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
718e3744 1095}
1096
01e24c4a
QY
1097/*
1098 * Hook for preprocessing command string before executing.
1099 *
1100 * All subscribers are called with the raw command string that is to be
1101 * executed. If any changes are to be made, a new string should be allocated
1102 * with MTYPE_TMP and *cmd_out updated to point to this new string. The caller
1103 * is then responsible for freeing this string.
1104 *
1105 * All processing functions must be mutually exclusive in their action, i.e. if
1106 * one subscriber decides to modify the command, all others must not modify it
1107 * when called. Feeding the output of one processing command into a subsequent
1108 * one is not supported.
1109 *
1110 * This hook is intentionally internal to the command processing system.
1111 *
1112 * cmd_in
1113 * The raw command string.
1114 *
1115 * cmd_out
1116 * The result of any processing.
1117 */
1118DECLARE_HOOK(cmd_execute,
0a334343 1119 (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a 1120 (vty, cmd_in, cmd_out));
0a334343 1121DEFINE_HOOK(cmd_execute, (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a
QY
1122 (vty, cmd_in, cmd_out));
1123
1124/* Hook executed after a CLI command. */
0a334343 1125DECLARE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a 1126 (vty, cmd_exec));
0a334343 1127DEFINE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a
QY
1128 (vty, cmd_exec));
1129
fe6b47b9
QY
1130/*
1131 * cmd_execute hook subscriber to handle `|` actions.
1132 */
1133static int handle_pipe_action(struct vty *vty, const char *cmd_in,
1134 char **cmd_out)
1135{
1136 /* look for `|` */
9f227e4c 1137 char *orig, *working, *token, *u;
fe6b47b9 1138 char *pipe = strstr(cmd_in, "| ");
2f272cb4 1139 int ret = 0;
fe6b47b9
QY
1140
1141 if (!pipe)
1142 return 0;
1143
1144 /* duplicate string for processing purposes, not including pipe */
1145 orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
1146
1147 /* retrieve action */
1148 token = strsep(&working, " ");
4f4060f6 1149 assert(token);
fe6b47b9
QY
1150
1151 /* match result to known actions */
1152 if (strmatch(token, "include")) {
1153 /* the remaining text should be a regexp */
1154 char *regexp = working;
5d806ec6
QY
1155
1156 if (!regexp) {
1157 vty_out(vty, "%% Need a regexp to filter with\n");
2f272cb4 1158 ret = 1;
5d806ec6
QY
1159 goto fail;
1160 }
1161
fe6b47b9 1162 bool succ = vty_set_include(vty, regexp);
0a334343 1163
fe6b47b9 1164 if (!succ) {
5d806ec6 1165 vty_out(vty, "%% Bad regexp '%s'\n", regexp);
2f272cb4 1166 ret = 1;
fe6b47b9
QY
1167 goto fail;
1168 }
2cddf2ff 1169 *cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
9f227e4c 1170 u = *cmd_out;
1171 strsep(&u, "|");
fe6b47b9 1172 } else {
5d806ec6 1173 vty_out(vty, "%% Unknown action '%s'\n", token);
2f272cb4 1174 ret = 1;
fe6b47b9
QY
1175 goto fail;
1176 }
1177
1178fail:
1179 XFREE(MTYPE_TMP, orig);
2f272cb4 1180 return ret;
fe6b47b9
QY
1181}
1182
1183static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
1184{
0b42d81a 1185 if (vty->filter)
fe6b47b9 1186 vty_set_include(vty, NULL);
0b42d81a 1187
fe6b47b9
QY
1188 return 0;
1189}
1190
01e24c4a
QY
1191int cmd_execute(struct vty *vty, const char *cmd,
1192 const struct cmd_element **matched, int vtysh)
1193{
1194 int ret;
1195 char *cmd_out = NULL;
2f272cb4 1196 const char *cmd_exec = NULL;
01e24c4a
QY
1197 vector vline;
1198
2f272cb4
IR
1199 ret = hook_call(cmd_execute, vty, cmd, &cmd_out);
1200 if (ret) {
1201 ret = CMD_WARNING;
1202 goto free;
1203 }
1204
01e24c4a
QY
1205 cmd_exec = cmd_out ? (const char *)cmd_out : cmd;
1206
1207 vline = cmd_make_strvec(cmd_exec);
1208
1209 if (vline) {
1210 ret = cmd_execute_command(vline, vty, matched, vtysh);
1211 cmd_free_strvec(vline);
1212 } else {
1213 ret = CMD_SUCCESS;
1214 }
1215
2f272cb4 1216free:
01e24c4a
QY
1217 hook_call(cmd_execute_done, vty, cmd_exec);
1218
0a22ddfb 1219 XFREE(MTYPE_TMP, cmd_out);
01e24c4a
QY
1220
1221 return ret;
1222}
1223
1224
bed578b8 1225/**
d62a17ae 1226 * Parse one line of config, walking up the parse tree attempting to find a
1227 * match
bed578b8
DS
1228 *
1229 * @param vty The vty context in which the command should be executed.
1230 * @param cmd Pointer where the struct cmd_element* of the match command
1231 * will be stored, if any. May be set to NULL if this info is
1232 * not needed.
d62a17ae 1233 * @param use_daemon Boolean to control whether or not we match on
1234 * CMD_SUCCESS_DAEMON
bed578b8
DS
1235 * or not.
1236 * @return The status of the command that has been executed or an error code
1237 * as to why no command could be executed.
1238 */
d62a17ae 1239int command_config_read_one_line(struct vty *vty,
7ab57d19
DS
1240 const struct cmd_element **cmd,
1241 uint32_t line_num, int use_daemon)
bed578b8 1242{
d62a17ae 1243 vector vline;
d62a17ae 1244 int ret;
e3476061 1245 unsigned up_level = 0;
bed578b8 1246
d62a17ae 1247 vline = cmd_make_strvec(vty->buf);
bed578b8 1248
d62a17ae 1249 /* In case of comment line */
1250 if (vline == NULL)
1251 return CMD_SUCCESS;
bed578b8 1252
d62a17ae 1253 /* Execute configuration command : this is strict match */
1254 ret = cmd_execute_command_strict(vline, vty, cmd);
bed578b8 1255
e3476061
DL
1256 /* The logic for trying parent nodes is in cmd_execute_command_real()
1257 * since calling ->node_exit() correctly is a bit involved. This is
1258 * also the only reason CMD_NO_LEVEL_UP exists.
1259 */
1260 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1261 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1262 && ret != CMD_SUCCESS && ret != CMD_WARNING
1263 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
1264 && ret != CMD_NO_LEVEL_UP)
1265 ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
1266 ++up_level);
1267
1268 if (ret == CMD_NO_LEVEL_UP)
1269 ret = CMD_ERR_NO_MATCH;
bed578b8 1270
b45d8ccc
DS
1271 if (ret != CMD_SUCCESS &&
1272 ret != CMD_WARNING &&
1273 ret != CMD_SUCCESS_DAEMON) {
7ab57d19
DS
1274 struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve));
1275
1276 memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
1277 ve->line_num = line_num;
1278 if (!vty->error)
1279 vty->error = list_new();
1280
1281 listnode_add(vty->error, ve);
1282 }
cbd7259d 1283
d62a17ae 1284 cmd_free_strvec(vline);
bed578b8 1285
d62a17ae 1286 return ret;
bed578b8
DS
1287}
1288
5689fe5f 1289/* Configuration make from file. */
d62a17ae 1290int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 1291{
d62a17ae 1292 int ret, error_ret = 0;
1293 *line_num = 0;
718e3744 1294
d62a17ae 1295 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
7ab57d19 1296 ++(*line_num);
13fbc82d 1297
7ab57d19 1298 ret = command_config_read_one_line(vty, NULL, *line_num, 0);
718e3744 1299
d62a17ae 1300 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1301 && ret != CMD_ERR_NOTHING_TODO)
1302 error_ret = ret;
1303 }
5689fe5f 1304
d62a17ae 1305 if (error_ret) {
1306 return error_ret;
1307 }
5689fe5f 1308
d62a17ae 1309 return CMD_SUCCESS;
718e3744 1310}
1311
5689fe5f 1312/* Configuration from terminal */
718e3744 1313DEFUN (config_terminal,
1314 config_terminal_cmd,
dc1c13c0 1315 "configure [terminal]",
718e3744 1316 "Configuration from vty interface\n"
1317 "Configuration terminal\n")
1318{
f344c66e 1319 return vty_config_enter(vty, false, false);
718e3744 1320}
1321
1322/* Enable command */
d0bfb22c 1323DEFUN (enable,
718e3744 1324 config_enable_cmd,
1325 "enable",
1326 "Turn on privileged mode command\n")
1327{
d62a17ae 1328 /* If enable password is NULL, change to ENABLE_NODE */
1329 if ((host.enable == NULL && host.enable_encrypt == NULL)
1330 || vty->type == VTY_SHELL_SERV)
1331 vty->node = ENABLE_NODE;
1332 else
1333 vty->node = AUTH_ENABLE_NODE;
718e3744 1334
d62a17ae 1335 return CMD_SUCCESS;
718e3744 1336}
1337
1338/* Disable command */
d0bfb22c 1339DEFUN (disable,
718e3744 1340 config_disable_cmd,
1341 "disable",
1342 "Turn off privileged mode command\n")
1343{
d62a17ae 1344 if (vty->node == ENABLE_NODE)
1345 vty->node = VIEW_NODE;
1346 return CMD_SUCCESS;
718e3744 1347}
1348
1349/* Down vty node level. */
1350DEFUN (config_exit,
1351 config_exit_cmd,
1352 "exit",
1353 "Exit current mode and down to previous mode\n")
0b84f294 1354{
d62a17ae 1355 cmd_exit(vty);
1356 return CMD_SUCCESS;
1357}
1358
791ded4a
DL
1359static int root_on_exit(struct vty *vty)
1360{
1361 if (vty_shell(vty))
1362 exit(0);
1363 else
1364 vty->status = VTY_CLOSE;
1365 return 0;
1366}
1367
d62a17ae 1368void cmd_exit(struct vty *vty)
1369{
24389580 1370 struct cmd_node *cnode = vector_lookup(cmdvec, vty->node);
1c2facd1 1371
791ded4a
DL
1372 if (cnode->node_exit) {
1373 if (!cnode->node_exit(vty))
1374 return;
d62a17ae 1375 }
791ded4a
DL
1376 if (cnode->parent_node)
1377 vty->node = cnode->parent_node;
dd90823b
CS
1378 if (vty->xpath_index > 0
1379 && vty_check_node_for_xpath_decrement(vty->node, cnode->node))
1c2facd1 1380 vty->xpath_index--;
718e3744 1381}
1382
f667a580
QY
1383/* ALIAS_FIXME */
1384DEFUN (config_quit,
1385 config_quit_cmd,
1386 "quit",
1387 "Exit current mode and down to previous mode\n")
1388{
d62a17ae 1389 return config_exit(self, vty, argc, argv);
f667a580
QY
1390}
1391
d0bfb22c 1392
718e3744 1393/* End of configuration. */
1394DEFUN (config_end,
1395 config_end_cmd,
1396 "end",
efd7904e 1397 "End current mode and change to enable mode.\n")
718e3744 1398{
cf09d3ca 1399 if (vty->config) {
f344c66e 1400 vty_config_exit(vty);
d62a17ae 1401 vty->node = ENABLE_NODE;
d62a17ae 1402 }
1403 return CMD_SUCCESS;
718e3744 1404}
1405
1406/* Show version. */
1407DEFUN (show_version,
1408 show_version_cmd,
1409 "show version",
1410 SHOW_STR
1411 "Displays zebra version\n")
1412{
d62a17ae 1413 vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION,
6b3ee3a0 1414 cmd_hostname_get() ? cmd_hostname_get() : "");
d62a17ae 1415 vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
e063f271 1416#ifdef ENABLE_VERSION_BUILD_CONFIG
d62a17ae 1417 vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
e063f271 1418#endif
d62a17ae 1419 return CMD_SUCCESS;
718e3744 1420}
1421
1422/* Help display function for all node. */
1423DEFUN (config_help,
1424 config_help_cmd,
1425 "help",
1426 "Description of the interactive help system\n")
1427{
d62a17ae 1428 vty_out(vty,
1429 "Quagga VTY provides advanced help feature. When you need help,\n\
61b7d449
DL
1430anytime at the command line please press '?'.\n\
1431\n\
1432If nothing matches, the help list will be empty and you must backup\n\
1433 until entering a '?' shows the available options.\n\
1434Two styles of help are provided:\n\
14351. Full help is available when you are ready to enter a\n\
1436command argument (e.g. 'show ?') and describes each possible\n\
1437argument.\n\
14382. Partial help is provided when an abbreviated argument is entered\n\
1439 and you want to know what arguments match the input\n\
1440 (e.g. 'show me?'.)\n\n");
d62a17ae 1441 return CMD_SUCCESS;
1442}
1443
1444static void permute(struct graph_node *start, struct vty *vty)
1445{
1446 static struct list *position = NULL;
1447 if (!position)
1448 position = list_new();
1449
1450 struct cmd_token *stok = start->data;
1451 struct graph_node *gnn;
1452 struct listnode *ln;
1453
1454 // recursive dfs
1455 listnode_add(position, start);
1456 for (unsigned int i = 0; i < vector_active(start->to); i++) {
1457 struct graph_node *gn = vector_slot(start->to, i);
1458 struct cmd_token *tok = gn->data;
1459 if (tok->attr == CMD_ATTR_HIDDEN
1460 || tok->attr == CMD_ATTR_DEPRECATED)
1461 continue;
1462 else if (tok->type == END_TKN || gn == start) {
1463 vty_out(vty, " ");
1464 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
1465 struct cmd_token *tt = gnn->data;
1466 if (tt->type < SPECIAL_TKN)
1467 vty_out(vty, " %s", tt->text);
1468 }
1469 if (gn == start)
1470 vty_out(vty, "...");
1471 vty_out(vty, "\n");
1472 } else {
1473 bool skip = false;
1474 if (stok->type == FORK_TKN && tok->type != FORK_TKN)
1475 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
1476 if (gnn == gn) {
1477 skip = true;
1478 break;
1479 }
1480 if (!skip)
1481 permute(gn, vty);
1482 }
1483 }
1484 list_delete_node(position, listtail(position));
1485}
1486
1487int cmd_list_cmds(struct vty *vty, int do_permute)
1488{
1489 struct cmd_node *node = vector_slot(cmdvec, vty->node);
1490
1491 if (do_permute)
1492 permute(vector_slot(node->cmdgraph->nodes, 0), vty);
1493 else {
1494 /* loop over all commands at this node */
154e9ca1 1495 const struct cmd_element *element = NULL;
d62a17ae 1496 for (unsigned int i = 0; i < vector_active(node->cmd_vector);
1497 i++)
1498 if ((element = vector_slot(node->cmd_vector, i))
1499 && element->attr != CMD_ATTR_DEPRECATED
1500 && element->attr != CMD_ATTR_HIDDEN)
1501 vty_out(vty, " %s\n", element->string);
1502 }
1503 return CMD_SUCCESS;
718e3744 1504}
1505
0b84f294
DL
1506/* Help display function for all node. */
1507DEFUN (config_list,
1508 config_list_cmd,
1509 "list [permutations]",
1510 "Print command list\n"
1511 "Print all possible command permutations\n")
1512{
d62a17ae 1513 return cmd_list_cmds(vty, argc == 2);
0b84f294
DL
1514}
1515
a2454870
QY
1516DEFUN (show_commandtree,
1517 show_commandtree_cmd,
1518 "show commandtree [permutations]",
1519 SHOW_STR
5a1945e4
DS
1520 "Show command tree\n"
1521 "Permutations that we are interested in\n")
a2454870 1522{
d62a17ae 1523 return cmd_list_cmds(vty, argc == 3);
a2454870
QY
1524}
1525
26fbe472
QY
1526DEFUN_HIDDEN(show_cli_graph,
1527 show_cli_graph_cmd,
1528 "show cli graph",
1529 SHOW_STR
1530 "CLI reflection\n"
1531 "Dump current command space as DOT graph\n")
1532{
1533 struct cmd_node *cn = vector_slot(cmdvec, vty->node);
1534 char *dot = cmd_graph_dump_dot(cn->cmdgraph);
1535
1536 vty_out(vty, "%s\n", dot);
1537 XFREE(MTYPE_TMP, dot);
1538 return CMD_SUCCESS;
1539}
1540
f806f29c 1541static int vty_write_config(struct vty *vty)
8efe88ea 1542{
d62a17ae 1543 size_t i;
1544 struct cmd_node *node;
8efe88ea 1545
f806f29c 1546 if (host.noconfig)
1547 return CMD_SUCCESS;
1548
5e6a9350
RW
1549 nb_cli_show_config_prepare(running_config, false);
1550
d62a17ae 1551 if (vty->type == VTY_TERM) {
1552 vty_out(vty, "\nCurrent configuration:\n");
1553 vty_out(vty, "!\n");
1554 }
8efe88ea 1555
ac4adef4
DL
1556 if (strcmp(frr_defaults_version(), FRR_VER_SHORT))
1557 vty_out(vty, "! loaded from %s\n", frr_defaults_version());
d62a17ae 1558 vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
ac4adef4 1559 vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
d62a17ae 1560 vty_out(vty, "!\n");
8efe88ea 1561
8685be73 1562 for (i = 0; i < vector_active(cmdvec); i++)
612c2c15
DL
1563 if ((node = vector_slot(cmdvec, i)) && node->config_write) {
1564 if ((*node->config_write)(vty))
8685be73
RW
1565 vty_out(vty, "!\n");
1566 }
8efe88ea 1567
d62a17ae 1568 if (vty->type == VTY_TERM) {
1569 vty_out(vty, "end\n");
1570 }
8efe88ea 1571
f806f29c 1572 return CMD_SUCCESS;
1573}
d862bffb 1574
f806f29c 1575static int file_write_config(struct vty *vty)
718e3744 1576{
d62a17ae 1577 int fd, dirfd;
1578 char *config_file, *slash;
1579 char *config_file_tmp = NULL;
1580 char *config_file_sav = NULL;
1581 int ret = CMD_WARNING;
1582 struct vty *file_vty;
1583 struct stat conf_stat;
1584
d62a17ae 1585 if (host.noconfig)
1586 return CMD_SUCCESS;
1587
1588 /* Check and see if we are operating under vtysh configuration */
1589 if (host.config == NULL) {
1590 vty_out(vty,
1591 "Can't save to configuration file, using vtysh.\n");
1592 return CMD_WARNING;
1593 }
1594
1595 /* Get filename. */
1596 config_file = host.config;
d0bfb22c 1597
056cfe49
DL
1598#ifndef O_DIRECTORY
1599#define O_DIRECTORY 0
1600#endif
d62a17ae 1601 slash = strrchr(config_file, '/');
1602 if (slash) {
1603 char *config_dir = XSTRDUP(MTYPE_TMP, config_file);
1604 config_dir[slash - config_file] = '\0';
1605 dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
1606 XFREE(MTYPE_TMP, config_dir);
1607 } else
1608 dirfd = open(".", O_DIRECTORY | O_RDONLY);
1609 /* if dirfd is invalid, directory sync fails, but we're still OK */
1610
9f73d2c9
QY
1611 size_t config_file_sav_sz = strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1;
1612 config_file_sav = XMALLOC(MTYPE_TMP, config_file_sav_sz);
1613 strlcpy(config_file_sav, config_file, config_file_sav_sz);
1614 strlcat(config_file_sav, CONF_BACKUP_EXT, config_file_sav_sz);
d62a17ae 1615
1616
1617 config_file_tmp = XMALLOC(MTYPE_TMP, strlen(config_file) + 8);
fc746f1c
QY
1618 snprintf(config_file_tmp, strlen(config_file) + 8, "%s.XXXXXX",
1619 config_file);
d62a17ae 1620
1621 /* Open file to configuration write. */
1622 fd = mkstemp(config_file_tmp);
1623 if (fd < 0) {
1624 vty_out(vty, "Can't open configuration file %s.\n",
1625 config_file_tmp);
1626 goto finished;
1627 }
1628 if (fchmod(fd, CONFIGFILE_MASK) != 0) {
1629 vty_out(vty, "Can't chmod configuration file %s: %s (%d).\n",
1630 config_file_tmp, safe_strerror(errno), errno);
1631 goto finished;
1632 }
1633
1634 /* Make vty for configuration file. */
1635 file_vty = vty_new();
1636 file_vty->wfd = fd;
1637 file_vty->type = VTY_FILE;
1638
1639 /* Config file header print. */
1640 vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! ");
1641 vty_time_print(file_vty, 1);
1642 vty_out(file_vty, "!\n");
1643 vty_write_config(file_vty);
1644 vty_close(file_vty);
1645
1646 if (stat(config_file, &conf_stat) >= 0) {
1647 if (unlink(config_file_sav) != 0)
1648 if (errno != ENOENT) {
1649 vty_out(vty,
1650 "Can't unlink backup configuration file %s.\n",
1651 config_file_sav);
1652 goto finished;
1653 }
1654 if (link(config_file, config_file_sav) != 0) {
1655 vty_out(vty,
1656 "Can't backup old configuration file %s.\n",
1657 config_file_sav);
1658 goto finished;
1659 }
1660 if (dirfd >= 0)
1661 fsync(dirfd);
1662 }
1663 if (rename(config_file_tmp, config_file) != 0) {
1664 vty_out(vty, "Can't save configuration file %s.\n",
1665 config_file);
1666 goto finished;
1667 }
1668 if (dirfd >= 0)
1669 fsync(dirfd);
1670
1671 vty_out(vty, "Configuration saved to %s\n", config_file);
1672 ret = CMD_SUCCESS;
05865c90 1673
1674finished:
d62a17ae 1675 if (ret != CMD_SUCCESS)
1676 unlink(config_file_tmp);
1677 if (dirfd >= 0)
1678 close(dirfd);
1679 XFREE(MTYPE_TMP, config_file_tmp);
1680 XFREE(MTYPE_TMP, config_file_sav);
1681 return ret;
718e3744 1682}
1683
f806f29c 1684/* Write current configuration into file. */
1685
1686DEFUN (config_write,
1687 config_write_cmd,
1688 "write [<file|memory|terminal>]",
1689 "Write running configuration to memory, network, or terminal\n"
1690 "Write to configuration file\n"
1691 "Write configuration currently in memory\n"
1692 "Write configuration to terminal\n")
1693{
1694 const int idx_type = 1;
1695
1696 // if command was 'write terminal' or 'write memory'
1697 if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal"))) {
1698 return vty_write_config(vty);
1699 }
1700
1701 return file_write_config(vty);
1702}
1703
d862bffb
QY
1704/* ALIAS_FIXME for 'write <terminal|memory>' */
1705DEFUN (show_running_config,
1706 show_running_config_cmd,
1707 "show running-config",
1708 SHOW_STR
f806f29c 1709 "running configuration (same as write terminal)\n")
d862bffb 1710{
f806f29c 1711 return vty_write_config(vty);
d862bffb 1712}
718e3744 1713
d862bffb
QY
1714/* ALIAS_FIXME for 'write file' */
1715DEFUN (copy_runningconf_startupconf,
1716 copy_runningconf_startupconf_cmd,
1717 "copy running-config startup-config",
1718 "Copy configuration\n"
1719 "Copy running config to... \n"
f806f29c 1720 "Copy running config to startup config (same as write file/memory)\n")
d862bffb 1721{
f806f29c 1722 return file_write_config(vty);
d862bffb
QY
1723}
1724/** -- **/
718e3744 1725
1726/* Write startup configuration into the terminal. */
1727DEFUN (show_startup_config,
1728 show_startup_config_cmd,
1729 "show startup-config",
1730 SHOW_STR
d0bfb22c 1731 "Contents of startup configuration\n")
718e3744 1732{
d62a17ae 1733 char buf[BUFSIZ];
1734 FILE *confp;
718e3744 1735
d62a17ae 1736 if (host.noconfig)
1737 return CMD_SUCCESS;
1738 if (host.config == NULL)
1739 return CMD_WARNING;
87f44e2f 1740
d62a17ae 1741 confp = fopen(host.config, "r");
1742 if (confp == NULL) {
1743 vty_out(vty, "Can't open configuration file [%s] due to '%s'\n",
1744 host.config, safe_strerror(errno));
1745 return CMD_WARNING;
1746 }
718e3744 1747
d62a17ae 1748 while (fgets(buf, BUFSIZ, confp)) {
1749 char *cp = buf;
718e3744 1750
d62a17ae 1751 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
1752 cp++;
1753 *cp = '\0';
718e3744 1754
d62a17ae 1755 vty_out(vty, "%s\n", buf);
1756 }
718e3744 1757
d62a17ae 1758 fclose(confp);
718e3744 1759
d62a17ae 1760 return CMD_SUCCESS;
718e3744 1761}
1762
6b3ee3a0
MK
1763int cmd_domainname_set(const char *domainname)
1764{
1765 XFREE(MTYPE_HOST, host.domainname);
1766 host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL;
1767 return CMD_SUCCESS;
1768}
1769
1770/* Hostname configuration */
60466a63
QY
1771DEFUN(config_domainname,
1772 domainname_cmd,
1773 "domainname WORD",
1774 "Set system's domain name\n"
1775 "This system's domain name\n")
6b3ee3a0
MK
1776{
1777 struct cmd_token *word = argv[1];
1778
fefa5e0f 1779 if (!isalpha((unsigned char)word->arg[0])) {
6b3ee3a0
MK
1780 vty_out(vty, "Please specify string starting with alphabet\n");
1781 return CMD_WARNING_CONFIG_FAILED;
1782 }
1783
1784 return cmd_domainname_set(word->arg);
1785}
1786
60466a63
QY
1787DEFUN(config_no_domainname,
1788 no_domainname_cmd,
1789 "no domainname [DOMAINNAME]",
1790 NO_STR
1791 "Reset system's domain name\n"
1792 "domain name of this router\n")
6b3ee3a0
MK
1793{
1794 return cmd_domainname_set(NULL);
1795}
1796
d62a17ae 1797int cmd_hostname_set(const char *hostname)
bff9c3e9 1798{
d62a17ae 1799 XFREE(MTYPE_HOST, host.name);
1800 host.name = hostname ? XSTRDUP(MTYPE_HOST, hostname) : NULL;
1801 return CMD_SUCCESS;
bff9c3e9
DL
1802}
1803
718e3744 1804/* Hostname configuration */
d0bfb22c 1805DEFUN (config_hostname,
718e3744 1806 hostname_cmd,
1807 "hostname WORD",
1808 "Set system's network name\n"
1809 "This system's network name\n")
1810{
d62a17ae 1811 struct cmd_token *word = argv[1];
d0bfb22c 1812
fefa5e0f 1813 if (!isalnum((unsigned char)word->arg[0])) {
63e653a2
LK
1814 vty_out(vty,
1815 "Please specify string starting with alphabet or number\n");
1816 return CMD_WARNING_CONFIG_FAILED;
1817 }
1818
1819 /* With reference to RFC 1123 Section 2.1 */
1820 if (strlen(word->arg) > HOSTNAME_LEN) {
1821 vty_out(vty, "Hostname length should be less than %d chars\n",
1822 HOSTNAME_LEN);
d62a17ae 1823 return CMD_WARNING_CONFIG_FAILED;
1824 }
718e3744 1825
d62a17ae 1826 return cmd_hostname_set(word->arg);
718e3744 1827}
1828
d0bfb22c 1829DEFUN (config_no_hostname,
718e3744 1830 no_hostname_cmd,
1831 "no hostname [HOSTNAME]",
1832 NO_STR
1833 "Reset system's network name\n"
1834 "Host name of this router\n")
1835{
d62a17ae 1836 return cmd_hostname_set(NULL);
718e3744 1837}
1838
1839/* VTY interface password set. */
f412b39a
DW
1840DEFUN (config_password,
1841 password_cmd,
98463e0a 1842 "password [(8-8)] WORD",
322e2d5c 1843 "Modify the terminal connection password\n"
718e3744 1844 "Specifies a HIDDEN password will follow\n"
d0bfb22c 1845 "The password string\n")
718e3744 1846{
d62a17ae 1847 int idx_8 = 1;
1848 int idx_word = 2;
1849 if (argc == 3) // '8' was specified
1850 {
1851 if (host.password)
1852 XFREE(MTYPE_HOST, host.password);
1853 host.password = NULL;
1854 if (host.password_encrypt)
1855 XFREE(MTYPE_HOST, host.password_encrypt);
1856 host.password_encrypt =
1857 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
1858 return CMD_SUCCESS;
1859 }
1860
fefa5e0f 1861 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 1862 vty_out(vty,
1863 "Please specify string starting with alphanumeric\n");
1864 return CMD_WARNING_CONFIG_FAILED;
1865 }
1866
1867 if (host.password)
1868 XFREE(MTYPE_HOST, host.password);
1869 host.password = NULL;
1870
1871 if (host.encrypt) {
1872 if (host.password_encrypt)
1873 XFREE(MTYPE_HOST, host.password_encrypt);
1874 host.password_encrypt =
1875 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
1876 } else
1877 host.password = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
1878
1879 return CMD_SUCCESS;
718e3744 1880}
1881
322e2d5c
PM
1882/* VTY interface password delete. */
1883DEFUN (no_config_password,
1884 no_password_cmd,
1885 "no password",
1886 NO_STR
1887 "Modify the terminal connection password\n")
1888{
1889 bool warned = false;
1890
1891 if (host.password) {
eb83f7ce 1892 if (!vty_shell_serv(vty)) {
4911ca9c 1893 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
1894 warned = true;
1895 }
322e2d5c
PM
1896 XFREE(MTYPE_HOST, host.password);
1897 }
1898 host.password = NULL;
1899
1900 if (host.password_encrypt) {
eb83f7ce 1901 if (!warned && !vty_shell_serv(vty))
4911ca9c 1902 vty_out(vty, NO_PASSWD_CMD_WARNING);
322e2d5c
PM
1903 XFREE(MTYPE_HOST, host.password_encrypt);
1904 }
1905 host.password_encrypt = NULL;
1906
1907 return CMD_SUCCESS;
1908}
1909
718e3744 1910/* VTY enable password set. */
f412b39a
DW
1911DEFUN (config_enable_password,
1912 enable_password_cmd,
98463e0a 1913 "enable password [(8-8)] WORD",
718e3744 1914 "Modify enable password parameters\n"
1915 "Assign the privileged level password\n"
1916 "Specifies a HIDDEN password will follow\n"
718e3744 1917 "The HIDDEN 'enable' password string\n")
1918{
d62a17ae 1919 int idx_8 = 2;
1920 int idx_word = 3;
1921
1922 /* Crypt type is specified. */
1923 if (argc == 4) {
1924 if (argv[idx_8]->arg[0] == '8') {
1925 if (host.enable)
1926 XFREE(MTYPE_HOST, host.enable);
1927 host.enable = NULL;
1928
1929 if (host.enable_encrypt)
1930 XFREE(MTYPE_HOST, host.enable_encrypt);
1931 host.enable_encrypt =
1932 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
1933
1934 return CMD_SUCCESS;
1935 } else {
1936 vty_out(vty, "Unknown encryption type.\n");
1937 return CMD_WARNING_CONFIG_FAILED;
1938 }
1939 }
1940
fefa5e0f 1941 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 1942 vty_out(vty,
1943 "Please specify string starting with alphanumeric\n");
1944 return CMD_WARNING_CONFIG_FAILED;
1945 }
1946
1947 if (host.enable)
1948 XFREE(MTYPE_HOST, host.enable);
1949 host.enable = NULL;
1950
1951 /* Plain password input. */
1952 if (host.encrypt) {
1953 if (host.enable_encrypt)
1954 XFREE(MTYPE_HOST, host.enable_encrypt);
1955 host.enable_encrypt =
1956 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
1957 } else
1958 host.enable = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
1959
1960 return CMD_SUCCESS;
718e3744 1961}
1962
718e3744 1963/* VTY enable password delete. */
f412b39a
DW
1964DEFUN (no_config_enable_password,
1965 no_enable_password_cmd,
718e3744 1966 "no enable password",
1967 NO_STR
1968 "Modify enable password parameters\n"
1969 "Assign the privileged level password\n")
1970{
322e2d5c
PM
1971 bool warned = false;
1972
1973 if (host.enable) {
eb83f7ce 1974 if (!vty_shell_serv(vty)) {
4911ca9c 1975 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
1976 warned = true;
1977 }
d62a17ae 1978 XFREE(MTYPE_HOST, host.enable);
322e2d5c 1979 }
d62a17ae 1980 host.enable = NULL;
718e3744 1981
322e2d5c 1982 if (host.enable_encrypt) {
eb83f7ce 1983 if (!warned && !vty_shell_serv(vty))
4911ca9c 1984 vty_out(vty, NO_PASSWD_CMD_WARNING);
d62a17ae 1985 XFREE(MTYPE_HOST, host.enable_encrypt);
322e2d5c 1986 }
d62a17ae 1987 host.enable_encrypt = NULL;
718e3744 1988
d62a17ae 1989 return CMD_SUCCESS;
718e3744 1990}
d0bfb22c 1991
718e3744 1992DEFUN (service_password_encrypt,
1993 service_password_encrypt_cmd,
1994 "service password-encryption",
1995 "Set up miscellaneous service\n"
1996 "Enable encrypted passwords\n")
1997{
d62a17ae 1998 if (host.encrypt)
1999 return CMD_SUCCESS;
718e3744 2000
d62a17ae 2001 host.encrypt = 1;
718e3744 2002
d62a17ae 2003 if (host.password) {
2004 if (host.password_encrypt)
2005 XFREE(MTYPE_HOST, host.password_encrypt);
2006 host.password_encrypt =
2007 XSTRDUP(MTYPE_HOST, zencrypt(host.password));
2008 }
2009 if (host.enable) {
2010 if (host.enable_encrypt)
2011 XFREE(MTYPE_HOST, host.enable_encrypt);
2012 host.enable_encrypt =
2013 XSTRDUP(MTYPE_HOST, zencrypt(host.enable));
2014 }
718e3744 2015
d62a17ae 2016 return CMD_SUCCESS;
718e3744 2017}
2018
2019DEFUN (no_service_password_encrypt,
2020 no_service_password_encrypt_cmd,
2021 "no service password-encryption",
2022 NO_STR
2023 "Set up miscellaneous service\n"
2024 "Enable encrypted passwords\n")
2025{
d62a17ae 2026 if (!host.encrypt)
2027 return CMD_SUCCESS;
718e3744 2028
d62a17ae 2029 host.encrypt = 0;
718e3744 2030
d62a17ae 2031 if (host.password_encrypt)
2032 XFREE(MTYPE_HOST, host.password_encrypt);
2033 host.password_encrypt = NULL;
718e3744 2034
d62a17ae 2035 if (host.enable_encrypt)
2036 XFREE(MTYPE_HOST, host.enable_encrypt);
2037 host.enable_encrypt = NULL;
718e3744 2038
d62a17ae 2039 return CMD_SUCCESS;
718e3744 2040}
2041
f412b39a
DW
2042DEFUN (config_terminal_length,
2043 config_terminal_length_cmd,
d0bfb22c 2044 "terminal length (0-512)",
718e3744 2045 "Set terminal line parameters\n"
2046 "Set number of lines on a screen\n"
2047 "Number of lines on screen (0 for no pausing)\n")
2048{
d62a17ae 2049 int idx_number = 2;
718e3744 2050
d62a17ae 2051 vty->lines = atoi(argv[idx_number]->arg);
718e3744 2052
d62a17ae 2053 return CMD_SUCCESS;
718e3744 2054}
2055
f412b39a
DW
2056DEFUN (config_terminal_no_length,
2057 config_terminal_no_length_cmd,
718e3744 2058 "terminal no length",
2059 "Set terminal line parameters\n"
2060 NO_STR
2061 "Set number of lines on a screen\n")
2062{
d62a17ae 2063 vty->lines = -1;
2064 return CMD_SUCCESS;
718e3744 2065}
2066
f412b39a
DW
2067DEFUN (service_terminal_length,
2068 service_terminal_length_cmd,
d0bfb22c 2069 "service terminal-length (0-512)",
718e3744 2070 "Set up miscellaneous service\n"
2071 "System wide terminal length configuration\n"
2072 "Number of lines of VTY (0 means no line control)\n")
2073{
d62a17ae 2074 int idx_number = 2;
718e3744 2075
d62a17ae 2076 host.lines = atoi(argv[idx_number]->arg);
718e3744 2077
d62a17ae 2078 return CMD_SUCCESS;
718e3744 2079}
2080
f412b39a
DW
2081DEFUN (no_service_terminal_length,
2082 no_service_terminal_length_cmd,
d0bfb22c 2083 "no service terminal-length [(0-512)]",
718e3744 2084 NO_STR
2085 "Set up miscellaneous service\n"
2086 "System wide terminal length configuration\n"
2087 "Number of lines of VTY (0 means no line control)\n")
2088{
d62a17ae 2089 host.lines = -1;
2090 return CMD_SUCCESS;
718e3744 2091}
2092
2885f72d 2093DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
2094 echo_cmd,
2095 "echo MESSAGE...",
2096 "Echo a message back to the vty\n"
2097 "The message to echo\n")
2885f72d 2098{
d62a17ae 2099 char *message;
2885f72d 2100
d62a17ae 2101 vty_out(vty, "%s\n",
2102 ((message = argv_concat(argv, argc, 1)) ? message : ""));
2103 if (message)
2104 XFREE(MTYPE_TMP, message);
2105 return CMD_SUCCESS;
2885f72d 2106}
2107
274a4a44 2108DEFUN (config_logmsg,
2109 config_logmsg_cmd,
199d90a1 2110 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 2111 "Send a message to enabled logging destinations\n"
2112 LOG_LEVEL_DESC
2113 "The message to send\n")
2114{
d62a17ae 2115 int idx_log_level = 1;
2116 int idx_message = 2;
2117 int level;
2118 char *message;
274a4a44 2119
0bdeb5e5
DL
2120 level = log_level_match(argv[idx_log_level]->arg);
2121 if (level == ZLOG_DISABLED)
d62a17ae 2122 return CMD_ERR_NO_MATCH;
274a4a44 2123
d62a17ae 2124 zlog(level, "%s",
2125 ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
2126 if (message)
2127 XFREE(MTYPE_TMP, message);
65efcfce 2128
d62a17ae 2129 return CMD_SUCCESS;
274a4a44 2130}
2131
9eed278b
DL
2132DEFUN (debug_memstats,
2133 debug_memstats_cmd,
2134 "[no] debug memstats-at-exit",
2135 NO_STR
2136 DEBUG_STR
2137 "Print memory type statistics at exit\n")
2138{
2139 debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
2140 return CMD_SUCCESS;
2141}
2142
d62a17ae 2143int cmd_banner_motd_file(const char *file)
7cfc61d3 2144{
d62a17ae 2145 int success = CMD_SUCCESS;
2146 char p[PATH_MAX];
2147 char *rpath;
2148 char *in;
7cfc61d3 2149
d62a17ae 2150 rpath = realpath(file, p);
2151 if (!rpath)
2152 return CMD_ERR_NO_FILE;
2153 in = strstr(rpath, SYSCONFDIR);
2154 if (in == rpath) {
0a22ddfb 2155 XFREE(MTYPE_HOST, host.motdfile);
d62a17ae 2156 host.motdfile = XSTRDUP(MTYPE_HOST, file);
2157 } else
2158 success = CMD_WARNING_CONFIG_FAILED;
1ee08155 2159
d62a17ae 2160 return success;
7cfc61d3
DS
2161}
2162
19d61463
DA
2163void cmd_banner_motd_line(const char *line)
2164{
e1b36e13 2165 XFREE(MTYPE_HOST, host.motd);
19d61463
DA
2166 host.motd = XSTRDUP(MTYPE_HOST, line);
2167}
2168
3b0c5d9a 2169DEFUN (banner_motd_file,
2170 banner_motd_file_cmd,
4d833e55 2171 "banner motd file FILE",
3b0c5d9a 2172 "Set banner\n"
2173 "Banner for motd\n"
2174 "Banner from a file\n"
2175 "Filename\n")
2176{
d62a17ae 2177 int idx_file = 3;
2178 const char *filename = argv[idx_file]->arg;
2179 int cmd = cmd_banner_motd_file(filename);
1ee08155 2180
d62a17ae 2181 if (cmd == CMD_ERR_NO_FILE)
2182 vty_out(vty, "%s does not exist", filename);
2183 else if (cmd == CMD_WARNING_CONFIG_FAILED)
2184 vty_out(vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155 2185
d62a17ae 2186 return cmd;
3b0c5d9a 2187}
718e3744 2188
19d61463
DA
2189DEFUN (banner_motd_line,
2190 banner_motd_line_cmd,
2191 "banner motd line LINE...",
2192 "Set banner\n"
2193 "Banner for motd\n"
2194 "Banner from an input\n"
2195 "Text\n")
2196{
2197 int idx = 0;
2198 char *motd;
2199
2200 argv_find(argv, argc, "LINE", &idx);
2201 motd = argv_concat(argv, argc, idx);
2202
2203 cmd_banner_motd_line(motd);
2204 XFREE(MTYPE_TMP, motd);
2205
2206 return CMD_SUCCESS;
2207}
2208
718e3744 2209DEFUN (banner_motd_default,
2210 banner_motd_default_cmd,
2211 "banner motd default",
2212 "Set banner string\n"
2213 "Strings for motd\n"
2214 "Default string\n")
2215{
19d61463 2216 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2217 return CMD_SUCCESS;
718e3744 2218}
2219
2220DEFUN (no_banner_motd,
2221 no_banner_motd_cmd,
2222 "no banner motd",
2223 NO_STR
2224 "Set banner string\n"
2225 "Strings for motd\n")
2226{
d62a17ae 2227 host.motd = NULL;
2228 if (host.motdfile)
2229 XFREE(MTYPE_HOST, host.motdfile);
2230 host.motdfile = NULL;
2231 return CMD_SUCCESS;
718e3744 2232}
2233
a83a5331
QY
2234DEFUN(find,
2235 find_cmd,
767f67a4 2236 "find REGEX...",
68912a20
QY
2237 "Find CLI command matching a regular expression\n"
2238 "Search pattern (POSIX regex)\n")
a83a5331 2239{
cf6c83e7
QY
2240 const struct cmd_node *node;
2241 const struct cmd_element *cli;
2242 vector clis;
a83a5331 2243
68912a20
QY
2244 regex_t exp = {};
2245
767f67a4 2246 char *pattern = argv_concat(argv, argc, 1);
68912a20 2247 int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
767f67a4 2248 XFREE(MTYPE_TMP, pattern);
68912a20
QY
2249
2250 if (cr != 0) {
2251 switch (cr) {
2252 case REG_BADBR:
2253 vty_out(vty, "%% Invalid {...} expression\n");
2254 break;
2255 case REG_BADRPT:
2256 vty_out(vty, "%% Bad repetition operator\n");
2257 break;
2258 case REG_BADPAT:
2259 vty_out(vty, "%% Regex syntax error\n");
2260 break;
2261 case REG_ECOLLATE:
2262 vty_out(vty, "%% Invalid collating element\n");
2263 break;
2264 case REG_ECTYPE:
2265 vty_out(vty, "%% Invalid character class name\n");
2266 break;
2267 case REG_EESCAPE:
2268 vty_out(vty,
2269 "%% Regex ended with escape character (\\)\n");
2270 break;
2271 case REG_ESUBREG:
2272 vty_out(vty,
2273 "%% Invalid number in \\digit construction\n");
2274 break;
2275 case REG_EBRACK:
2276 vty_out(vty, "%% Unbalanced square brackets\n");
2277 break;
2278 case REG_EPAREN:
2279 vty_out(vty, "%% Unbalanced parentheses\n");
2280 break;
2281 case REG_EBRACE:
2282 vty_out(vty, "%% Unbalanced braces\n");
2283 break;
2284 case REG_ERANGE:
2285 vty_out(vty,
2286 "%% Invalid endpoint in range expression\n");
2287 break;
2288 case REG_ESPACE:
2289 vty_out(vty, "%% Failed to compile (out of memory)\n");
2290 break;
2291 }
2292
2293 goto done;
2294 }
2295
2296
a83a5331 2297 for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
cf6c83e7 2298 node = vector_slot(cmdvec, i);
a83a5331
QY
2299 if (!node)
2300 continue;
cf6c83e7 2301 clis = node->cmd_vector;
a83a5331 2302 for (unsigned int j = 0; j < vector_active(clis); j++) {
cf6c83e7 2303 cli = vector_slot(clis, j);
68912a20
QY
2304
2305 if (regexec(&exp, cli->string, 0, NULL, 0) == 0)
cf6c83e7 2306 vty_out(vty, " (%s) %s\n",
f4b8291f 2307 node->name, cli->string);
a83a5331
QY
2308 }
2309 }
2310
68912a20
QY
2311done:
2312 regfree(&exp);
a83a5331
QY
2313 return CMD_SUCCESS;
2314}
2315
fa22080d 2316#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
5f98c815
QY
2317DEFUN(script,
2318 script_cmd,
2319 "script SCRIPT",
2320 "Test command - execute a script\n"
2321 "Script name (same as filename in /etc/frr/scripts/\n")
2322{
3d19ffc5 2323 struct prefix p;
45e56ec4
DS
2324
2325 (void)str2prefix("1.2.3.4/24", &p);
3d19ffc5
QY
2326
2327 struct frrscript *fs = frrscript_load(argv[1]->arg, NULL);
5f98c815 2328
3d19ffc5
QY
2329 if (fs == NULL) {
2330 vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n",
2331 argv[1]->arg);
2332 } else {
f869ab17 2333 int ret = frrscript_call(fs, NULL);
3d19ffc5
QY
2334 vty_out(vty, "Script result: %d\n", ret);
2335 }
5f98c815
QY
2336
2337 return CMD_SUCCESS;
2338}
2339#endif
2340
718e3744 2341/* Set config filename. Called from vty.c */
d62a17ae 2342void host_config_set(const char *filename)
718e3744 2343{
0a22ddfb 2344 XFREE(MTYPE_HOST, host.config);
d62a17ae 2345 host.config = XSTRDUP(MTYPE_HOST, filename);
718e3744 2346}
2347
d62a17ae 2348const char *host_config_get(void)
57387fb2 2349{
d62a17ae 2350 return host.config;
57387fb2
CF
2351}
2352
d62a17ae 2353void install_default(enum node_type node)
718e3744 2354{
01485adb
DL
2355 _install_element(node, &config_exit_cmd);
2356 _install_element(node, &config_quit_cmd);
2357 _install_element(node, &config_end_cmd);
2358 _install_element(node, &config_help_cmd);
2359 _install_element(node, &config_list_cmd);
2360 _install_element(node, &show_cli_graph_cmd);
2361 _install_element(node, &find_cmd);
718e3744 2362
01485adb
DL
2363 _install_element(node, &config_write_cmd);
2364 _install_element(node, &show_running_config_cmd);
7f059ea6 2365
01485adb 2366 _install_element(node, &autocomplete_cmd);
1c2facd1
RW
2367
2368 nb_cli_install_default(node);
718e3744 2369}
2370
87f44e2f
DL
2371/* Initialize command interface. Install basic nodes and commands.
2372 *
2373 * terminal = 0 -- vtysh / no logging, no config control
2374 * terminal = 1 -- normal daemon
9473e340 2375 * terminal = -1 -- watchfrr / no logging, but minimal config control */
d62a17ae 2376void cmd_init(int terminal)
2377{
419cd5a0
MK
2378 struct utsname names;
2379
419cd5a0 2380 uname(&names);
d62a17ae 2381 qobj_init();
2382
fe6b47b9
QY
2383 /* register command preprocessors */
2384 hook_register(cmd_execute, handle_pipe_action);
2385 hook_register(cmd_execute_done, handle_pipe_action_done);
2386
d62a17ae 2387 varhandlers = list_new();
2388
2389 /* Allocate initial top vector of commands. */
2390 cmdvec = vector_init(VECTOR_MIN_SIZE);
2391
2392 /* Default host value settings. */
419cd5a0
MK
2393 host.name = XSTRDUP(MTYPE_HOST, names.nodename);
2394#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
6b3ee3a0
MK
2395 if ((strcmp(names.domainname, "(none)") == 0))
2396 host.domainname = NULL;
2397 else
2398 host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
419cd5a0
MK
2399#else
2400 host.domainname = NULL;
2401#endif
d62a17ae 2402 host.password = NULL;
2403 host.enable = NULL;
d62a17ae 2404 host.config = NULL;
2405 host.noconfig = (terminal < 0);
2406 host.lines = -1;
19d61463 2407 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2408 host.motdfile = NULL;
2409
2410 /* Install top nodes. */
612c2c15
DL
2411 install_node(&view_node);
2412 install_node(&enable_node);
2413 install_node(&auth_node);
2414 install_node(&auth_enable_node);
2415 install_node(&config_node);
d62a17ae 2416
2417 /* Each node's basic commands. */
2418 install_element(VIEW_NODE, &show_version_cmd);
a83a5331
QY
2419 install_element(ENABLE_NODE, &show_startup_config_cmd);
2420
d62a17ae 2421 if (terminal) {
85a6806d
MS
2422 install_element(ENABLE_NODE, &debug_memstats_cmd);
2423
d62a17ae 2424 install_element(VIEW_NODE, &config_list_cmd);
2425 install_element(VIEW_NODE, &config_exit_cmd);
2426 install_element(VIEW_NODE, &config_quit_cmd);
2427 install_element(VIEW_NODE, &config_help_cmd);
2428 install_element(VIEW_NODE, &config_enable_cmd);
2429 install_element(VIEW_NODE, &config_terminal_length_cmd);
2430 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
d62a17ae 2431 install_element(VIEW_NODE, &show_commandtree_cmd);
2432 install_element(VIEW_NODE, &echo_cmd);
2433 install_element(VIEW_NODE, &autocomplete_cmd);
a83a5331 2434 install_element(VIEW_NODE, &find_cmd);
fa22080d 2435#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
3d19ffc5
QY
2436 install_element(VIEW_NODE, &script_cmd);
2437#endif
2438
d62a17ae 2439
d62a17ae 2440 install_element(ENABLE_NODE, &config_end_cmd);
2441 install_element(ENABLE_NODE, &config_disable_cmd);
2442 install_element(ENABLE_NODE, &config_terminal_cmd);
2443 install_element(ENABLE_NODE, &copy_runningconf_startupconf_cmd);
2444 install_element(ENABLE_NODE, &config_write_cmd);
2445 install_element(ENABLE_NODE, &show_running_config_cmd);
d62a17ae 2446 install_element(ENABLE_NODE, &config_logmsg_cmd);
a83a5331 2447
d62a17ae 2448 install_default(CONFIG_NODE);
2449
2450 thread_cmd_init();
2451 workqueue_cmd_init();
2452 hash_cmd_init();
2453 }
2454
2455 install_element(CONFIG_NODE, &hostname_cmd);
2456 install_element(CONFIG_NODE, &no_hostname_cmd);
6b3ee3a0
MK
2457 install_element(CONFIG_NODE, &domainname_cmd);
2458 install_element(CONFIG_NODE, &no_domainname_cmd);
d62a17ae 2459
2460 if (terminal > 0) {
0bdeb5e5
DL
2461 full_cli = true;
2462
85a6806d
MS
2463 install_element(CONFIG_NODE, &debug_memstats_cmd);
2464
d62a17ae 2465 install_element(CONFIG_NODE, &password_cmd);
322e2d5c 2466 install_element(CONFIG_NODE, &no_password_cmd);
d62a17ae 2467 install_element(CONFIG_NODE, &enable_password_cmd);
2468 install_element(CONFIG_NODE, &no_enable_password_cmd);
2469
d62a17ae 2470 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
2471 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
2472 install_element(CONFIG_NODE, &banner_motd_default_cmd);
2473 install_element(CONFIG_NODE, &banner_motd_file_cmd);
19d61463 2474 install_element(CONFIG_NODE, &banner_motd_line_cmd);
d62a17ae 2475 install_element(CONFIG_NODE, &no_banner_motd_cmd);
2476 install_element(CONFIG_NODE, &service_terminal_length_cmd);
2477 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
2478
0bdeb5e5 2479 log_cmd_init();
d62a17ae 2480 vrf_install_commands();
2481 }
af2567b6
DL
2482
2483#ifdef DEV_BUILD
d62a17ae 2484 grammar_sandbox_init();
af2567b6 2485#endif
718e3744 2486}
228da428 2487
4d762f26 2488void cmd_terminate(void)
d62a17ae 2489{
2490 struct cmd_node *cmd_node;
2491
5d806ec6
QY
2492 hook_unregister(cmd_execute, handle_pipe_action);
2493 hook_unregister(cmd_execute_done, handle_pipe_action_done);
2494
d62a17ae 2495 if (cmdvec) {
2496 for (unsigned int i = 0; i < vector_active(cmdvec); i++)
2497 if ((cmd_node = vector_slot(cmdvec, i)) != NULL) {
2498 // deleting the graph delets the cmd_element as
2499 // well
2500 graph_delete_graph(cmd_node->cmdgraph);
2501 vector_free(cmd_node->cmd_vector);
2502 hash_clean(cmd_node->cmd_hash, NULL);
2503 hash_free(cmd_node->cmd_hash);
2504 cmd_node->cmd_hash = NULL;
2505 }
2506
2507 vector_free(cmdvec);
2508 cmdvec = NULL;
2509 }
2510
0a22ddfb
QY
2511 XFREE(MTYPE_HOST, host.name);
2512 XFREE(MTYPE_HOST, host.domainname);
2513 XFREE(MTYPE_HOST, host.password);
2514 XFREE(MTYPE_HOST, host.password_encrypt);
2515 XFREE(MTYPE_HOST, host.enable);
2516 XFREE(MTYPE_HOST, host.enable_encrypt);
0a22ddfb
QY
2517 XFREE(MTYPE_HOST, host.motdfile);
2518 XFREE(MTYPE_HOST, host.config);
19d61463 2519 XFREE(MTYPE_HOST, host.motd);
d62a17ae 2520
6a154c88 2521 list_delete(&varhandlers);
d62a17ae 2522 qobj_finish();
228da428 2523}