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