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