]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
*: Convert `struct event_master` to `struct event_loop`
[mirror_frr.git] / lib / command.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
274a4a44 2/*
9547b5d0
QY
3 * CLI backend interface.
4 *
5 * --
6 * Copyright (C) 2016 Cumulus Networks, Inc.
7 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
8 * Copyright (C) 2013 by Open Source Routing.
9 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
9547b5d0 10 */
718e3744 11
12#include <zebra.h>
fe011935 13#include <lib/version.h>
718e3744 14
fe011935
QY
15#include "command.h"
16#include "frrstr.h"
718e3744 17#include "memory.h"
18#include "log.h"
0bdeb5e5 19#include "log_vty.h"
cb37cb33 20#include "event.h"
b21b19c5 21#include "vector.h"
d0bfb22c 22#include "linklist.h"
b21b19c5 23#include "vty.h"
354d119a 24#include "workqueue.h"
19dc275e 25#include "vrf.h"
d0bfb22c 26#include "command_match.h"
5894e76d 27#include "command_graph.h"
1bf9f027 28#include "qobj.h"
8efe88ea 29#include "defaults.h"
9eed278b 30#include "libfrr.h"
bd74dc61 31#include "jhash.h"
01e24c4a 32#include "hook.h"
481bc15f 33#include "lib_errors.h"
1c2facd1 34#include "northbound_cli.h"
5920b3eb 35#include "network.h"
cf00164b 36#include "routemap.h"
d0bfb22c 37
3d19ffc5
QY
38#include "frrscript.h"
39
bf8d3d6a
DL
40DEFINE_MTYPE_STATIC(LIB, HOST, "Host config");
41DEFINE_MTYPE(LIB, COMPLETION, "Completion item");
4a1ab8e4 42
26fbe472
QY
43#define item(x) \
44 { \
45 x, #x \
46 }
47
48/* clang-format off */
49const struct message tokennames[] = {
50 item(WORD_TKN),
51 item(VARIABLE_TKN),
52 item(RANGE_TKN),
53 item(IPV4_TKN),
54 item(IPV4_PREFIX_TKN),
55 item(IPV6_TKN),
56 item(IPV6_PREFIX_TKN),
57 item(MAC_TKN),
58 item(MAC_PREFIX_TKN),
8079a413 59 item(ASNUM_TKN),
26fbe472
QY
60 item(FORK_TKN),
61 item(JOIN_TKN),
62 item(START_TKN),
63 item(END_TKN),
90c8406c 64 item(NEG_ONLY_TKN),
26fbe472
QY
65 {0},
66};
26fbe472 67/* clang-format on */
a83a5331 68
718e3744 69/* Command vector which includes some level of command lists. Normally
70 each daemon maintains each own cmdvec. */
eb820afe 71vector cmdvec = NULL;
718e3744 72
73/* Host information structure. */
74struct host host;
75
0e06eb8b
DL
76/* for vtysh, put together CLI trees only when switching into node */
77static bool defer_cli_tree;
78
419cd5a0
MK
79/*
80 * Returns host.name if any, otherwise
81 * it returns the system hostname.
82 */
6b3ee3a0 83const char *cmd_hostname_get(void)
419cd5a0
MK
84{
85 return host.name;
86}
87
88/*
89 * Returns unix domainname
90 */
6b3ee3a0 91const char *cmd_domainname_get(void)
419cd5a0
MK
92{
93 return host.domainname;
94}
95
46b48b33
DS
96const char *cmd_system_get(void)
97{
98 return host.system;
99}
100
101const char *cmd_release_get(void)
102{
103 return host.release;
104}
105
106const char *cmd_version_get(void)
107{
108 return host.version;
109}
110
ac156aec
DA
111bool cmd_allow_reserved_ranges_get(void)
112{
113 return host.allow_reserved_ranges;
114}
115
234f6fd4
DA
116const char *cmd_software_version_get(void)
117{
118 return FRR_FULL_NAME "/" FRR_VERSION;
119}
120
791ded4a
DL
121static int root_on_exit(struct vty *vty);
122
718e3744 123/* Standard command node structures. */
d62a17ae 124static struct cmd_node auth_node = {
f4b8291f 125 .name = "auth",
62b346ee
DL
126 .node = AUTH_NODE,
127 .prompt = "Password: ",
718e3744 128};
129
d62a17ae 130static struct cmd_node view_node = {
f4b8291f 131 .name = "view",
62b346ee
DL
132 .node = VIEW_NODE,
133 .prompt = "%s> ",
791ded4a 134 .node_exit = root_on_exit,
718e3744 135};
136
d62a17ae 137static struct cmd_node auth_enable_node = {
f4b8291f 138 .name = "auth enable",
62b346ee
DL
139 .node = AUTH_ENABLE_NODE,
140 .prompt = "Password: ",
718e3744 141};
142
d62a17ae 143static struct cmd_node enable_node = {
f4b8291f 144 .name = "enable",
62b346ee
DL
145 .node = ENABLE_NODE,
146 .prompt = "%s# ",
791ded4a 147 .node_exit = root_on_exit,
718e3744 148};
149
612c2c15 150static int config_write_host(struct vty *vty);
62b346ee 151static struct cmd_node config_node = {
f4b8291f 152 .name = "config",
62b346ee 153 .node = CONFIG_NODE,
24389580 154 .parent_node = ENABLE_NODE,
62b346ee 155 .prompt = "%s(config)# ",
612c2c15 156 .config_write = config_write_host,
791ded4a 157 .node_exit = vty_config_node_exit,
62b346ee 158};
6590f2c3 159
cb585b65 160/* This is called from main when a daemon is invoked with -v or --version. */
d62a17ae 161void print_version(const char *progname)
6590f2c3 162{
d62a17ae 163 printf("%s version %s\n", progname, FRR_VERSION);
164 printf("%s\n", FRR_COPYRIGHT);
e063f271 165#ifdef ENABLE_VERSION_BUILD_CONFIG
d62a17ae 166 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
e063f271 167#endif
6590f2c3 168}
169
d62a17ae 170char *argv_concat(struct cmd_token **argv, int argc, int shift)
171{
a6a87d63 172 int cnt = MAX(argc - shift, 0);
173 const char *argstr[cnt + 1];
174
175 if (!cnt)
176 return NULL;
fe011935
QY
177
178 for (int i = 0; i < cnt; i++)
179 argstr[i] = argv[i + shift]->arg;
180
181 return frrstr_join(argstr, cnt, " ");
182}
183
184vector cmd_make_strvec(const char *string)
185{
186 if (!string)
d62a17ae 187 return NULL;
fe011935
QY
188
189 const char *copy = string;
190
191 /* skip leading whitespace */
fefa5e0f 192 while (isspace((unsigned char)*copy) && *copy != '\0')
fe011935
QY
193 copy++;
194
195 /* if the entire string was whitespace or a comment, return */
196 if (*copy == '\0' || *copy == '!' || *copy == '#')
197 return NULL;
198
0a334343 199 vector result = frrstr_split_vec(copy, "\n\r\t ");
fe011935
QY
200
201 for (unsigned int i = 0; i < vector_active(result); i++) {
202 if (strlen(vector_slot(result, i)) == 0) {
203 XFREE(MTYPE_TMP, vector_slot(result, i));
f428cb8a 204 vector_unset(result, i);
fe011935 205 }
d62a17ae 206 }
f428cb8a
QY
207
208 vector_compact(result);
209
fe011935
QY
210 return result;
211}
212
213void cmd_free_strvec(vector v)
214{
215 frrstr_strvec_free(v);
718e3744 216}
217
ae19d7dd
QY
218/**
219 * Convenience function for accessing argv data.
220 *
221 * @param argc
222 * @param argv
223 * @param text definition snippet of the desired token
224 * @param index the starting index, and where to store the
225 * index of the found token if it exists
226 * @return 1 if found, 0 otherwise
227 */
d62a17ae 228int argv_find(struct cmd_token **argv, int argc, const char *text, int *index)
ae19d7dd 229{
d62a17ae 230 int found = 0;
231 for (int i = *index; i < argc && found == 0; i++)
232 if ((found = strmatch(text, argv[i]->text)))
233 *index = i;
234 return found;
ae19d7dd
QY
235}
236
d8b87afe 237static unsigned int cmd_hash_key(const void *p)
274f29b2 238{
bd74dc61
DS
239 int size = sizeof(p);
240
241 return jhash(p, size, 0);
274f29b2
PJ
242}
243
74df8d6d 244static bool cmd_hash_cmp(const void *a, const void *b)
274f29b2 245{
d62a17ae 246 return a == b;
274f29b2
PJ
247}
248
718e3744 249/* Install top node of command vector. */
612c2c15 250void install_node(struct cmd_node *node)
718e3744 251{
c81d78cf
DS
252#define CMD_HASH_STR_SIZE 256
253 char hash_name[CMD_HASH_STR_SIZE];
254
d62a17ae 255 vector_set_index(cmdvec, node->node, node);
d62a17ae 256 node->cmdgraph = graph_new();
257 node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
258 // add start node
9eebf97e 259 struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
d62a17ae 260 graph_new_node(node->cmdgraph, token,
261 (void (*)(void *)) & cmd_token_del);
c81d78cf
DS
262
263 snprintf(hash_name, sizeof(hash_name), "Command Hash: %s", node->name);
264 node->cmd_hash =
265 hash_create_size(16, cmd_hash_key, cmd_hash_cmp, hash_name);
718e3744 266}
267
718e3744 268/* Return prompt character of specified node. */
d62a17ae 269const char *cmd_prompt(enum node_type node)
718e3744 270{
d62a17ae 271 struct cmd_node *cnode;
718e3744 272
d62a17ae 273 cnode = vector_slot(cmdvec, node);
274 return cnode->prompt;
718e3744 275}
276
0e06eb8b
DL
277void cmd_defer_tree(bool val)
278{
279 defer_cli_tree = val;
280}
281
718e3744 282/* Install a command into a node. */
01485adb 283void _install_element(enum node_type ntype, const struct cmd_element *cmd)
718e3744 284{
d62a17ae 285 struct cmd_node *cnode;
d0bfb22c 286
d62a17ae 287 /* cmd_init hasn't been called */
288 if (!cmdvec) {
289 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
290 __func__);
291 return;
292 }
ebacb4ed 293
3cbb67f2 294 cnode = vector_lookup(cmdvec, ntype);
718e3744 295
d62a17ae 296 if (cnode == NULL) {
297 fprintf(stderr,
3cbb67f2 298 "%s[%s]:\n"
f4b8291f 299 "\tnode %d does not exist.\n"
3cbb67f2 300 "\tplease call install_node() before install_element()\n",
f4b8291f 301 cmd->name, cmd->string, ntype);
d62a17ae 302 exit(EXIT_FAILURE);
303 }
ebacb4ed 304
154e9ca1 305 if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) {
d62a17ae 306 fprintf(stderr,
3cbb67f2
DL
307 "%s[%s]:\n"
308 "\tnode %d (%s) already has this command installed.\n"
309 "\tduplicate install_element call?\n",
f4b8291f 310 cmd->name, cmd->string, ntype, cnode->name);
d62a17ae 311 return;
312 }
ebacb4ed 313
8e3aae66 314 (void)hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern);
ebacb4ed 315
0e06eb8b
DL
316 if (cnode->graph_built || !defer_cli_tree) {
317 struct graph *graph = graph_new();
318 struct cmd_token *token =
9eebf97e 319 cmd_token_new(START_TKN, 0, NULL, NULL);
0e06eb8b
DL
320 graph_new_node(graph, token,
321 (void (*)(void *)) & cmd_token_del);
322
323 cmd_graph_parse(graph, cmd);
324 cmd_graph_names(graph);
325 cmd_graph_merge(cnode->cmdgraph, graph, +1);
326 graph_delete_graph(graph);
327
328 cnode->graph_built = true;
329 }
330
331 vector_set(cnode->cmd_vector, (void *)cmd);
332
333 if (ntype == VIEW_NODE)
334 _install_element(ENABLE_NODE, cmd);
335}
336
337static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
338{
339 struct cmd_node *cnode = arg;
340 const struct cmd_element *cmd = hb->data;
d62a17ae 341 struct graph *graph = graph_new();
9eebf97e 342 struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
0e06eb8b 343
d62a17ae 344 graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
de8f7a39 345
d62a17ae 346 cmd_graph_parse(graph, cmd);
347 cmd_graph_names(graph);
348 cmd_graph_merge(cnode->cmdgraph, graph, +1);
349 graph_delete_graph(graph);
0e06eb8b 350}
de8f7a39 351
0e06eb8b
DL
352void cmd_finalize_node(struct cmd_node *cnode)
353{
354 if (cnode->graph_built)
355 return;
735e62a0 356
0e06eb8b
DL
357 hash_iterate(cnode->cmd_hash, cmd_finalize_iter, cnode);
358 cnode->graph_built = true;
718e3744 359}
360
154e9ca1 361void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
de8f7a39 362{
d62a17ae 363 struct cmd_node *cnode;
de8f7a39 364
d62a17ae 365 /* cmd_init hasn't been called */
366 if (!cmdvec) {
367 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
368 __func__);
369 return;
370 }
de8f7a39 371
3cbb67f2 372 cnode = vector_lookup(cmdvec, ntype);
de8f7a39 373
d62a17ae 374 if (cnode == NULL) {
375 fprintf(stderr,
3cbb67f2 376 "%s[%s]:\n"
f4b8291f 377 "\tnode %d does not exist.\n"
3cbb67f2 378 "\tplease call install_node() before uninstall_element()\n",
f4b8291f 379 cmd->name, cmd->string, ntype);
d62a17ae 380 exit(EXIT_FAILURE);
381 }
de8f7a39 382
154e9ca1 383 if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) {
d62a17ae 384 fprintf(stderr,
3cbb67f2
DL
385 "%s[%s]:\n"
386 "\tnode %d (%s) does not have this command installed.\n"
387 "\tduplicate uninstall_element call?\n",
f4b8291f 388 cmd->name, cmd->string, ntype, cnode->name);
d62a17ae 389 return;
390 }
de8f7a39 391
154e9ca1 392 vector_unset_value(cnode->cmd_vector, (void *)cmd);
de8f7a39 393
0e06eb8b
DL
394 if (cnode->graph_built) {
395 struct graph *graph = graph_new();
396 struct cmd_token *token =
9eebf97e 397 cmd_token_new(START_TKN, 0, NULL, NULL);
0e06eb8b
DL
398 graph_new_node(graph, token,
399 (void (*)(void *)) & cmd_token_del);
400
401 cmd_graph_parse(graph, cmd);
402 cmd_graph_names(graph);
403 cmd_graph_merge(cnode->cmdgraph, graph, -1);
404 graph_delete_graph(graph);
405 }
de8f7a39 406
d62a17ae 407 if (ntype == VIEW_NODE)
408 uninstall_element(ENABLE_NODE, cmd);
de8f7a39
DL
409}
410
411
2d362d10 412static const unsigned char itoa64[] =
d62a17ae 413 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
718e3744 414
d62a17ae 415static void to64(char *s, long v, int n)
718e3744 416{
d62a17ae 417 while (--n >= 0) {
418 *s++ = itoa64[v & 0x3f];
419 v >>= 6;
420 }
718e3744 421}
422
d62a17ae 423static char *zencrypt(const char *passwd)
718e3744 424{
d62a17ae 425 char salt[6];
426 struct timeval tv;
718e3744 427
d62a17ae 428 gettimeofday(&tv, 0);
d0bfb22c 429
5920b3eb 430 to64(&salt[0], frr_weak_random(), 3);
d62a17ae 431 to64(&salt[3], tv.tv_usec, 3);
432 salt[5] = '\0';
718e3744 433
d62a17ae 434 return crypt(passwd, salt);
718e3744 435}
436
0bdeb5e5
DL
437static bool full_cli;
438
718e3744 439/* This function write configuration of this host. */
d62a17ae 440static int config_write_host(struct vty *vty)
441{
a7141b85 442 const char *name;
d62a17ae 443
a7141b85
DS
444 name = cmd_hostname_get();
445 if (name && name[0] != '\0')
446 vty_out(vty, "hostname %s\n", name);
447
448 name = cmd_domainname_get();
449 if (name && name[0] != '\0')
450 vty_out(vty, "domainname %s\n", name);
3b103fec 451
ac156aec
DA
452 if (cmd_allow_reserved_ranges_get())
453 vty_out(vty, "allow-reserved-ranges\n");
454
0204baa8 455 /* The following are all configuration commands that are not sent to
3518f352
DS
456 * watchfrr. For instance watchfrr is hardcoded to log to syslog so
457 * we would always display 'log syslog informational' in the config
458 * which would cause other daemons to then switch to syslog when they
459 * parse frr.conf.
460 */
0bdeb5e5 461 if (full_cli) {
0204baa8
DW
462 if (host.encrypt) {
463 if (host.password_encrypt)
3518f352
DS
464 vty_out(vty, "password 8 %s\n",
465 host.password_encrypt);
0204baa8
DW
466 if (host.enable_encrypt)
467 vty_out(vty, "enable password 8 %s\n",
468 host.enable_encrypt);
469 } else {
470 if (host.password)
471 vty_out(vty, "password %s\n", host.password);
472 if (host.enable)
3518f352
DS
473 vty_out(vty, "enable password %s\n",
474 host.enable);
0204baa8 475 }
0bdeb5e5 476 log_config_write(vty);
d62a17ae 477
45f01188
DL
478 /* print disable always, but enable only if default is flipped
479 * => prep for future removal of compile-time knob
480 */
481 if (!cputime_enabled)
482 vty_out(vty, "no service cputime-stats\n");
483#ifdef EXCLUDE_CPU_TIME
484 else
485 vty_out(vty, "service cputime-stats\n");
486#endif
487
488 if (!cputime_threshold)
489 vty_out(vty, "no service cputime-warning\n");
490#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
491 else /* again, always print non-default */
492#else
493 else if (cputime_threshold != 5000000)
494#endif
495 vty_out(vty, "service cputime-warning %lu\n",
ef78e4fd 496 cputime_threshold / 1000);
45f01188
DL
497
498 if (!walltime_threshold)
499 vty_out(vty, "no service walltime-warning\n");
500#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000
501 else /* again, always print non-default */
502#else
503 else if (walltime_threshold != 5000000)
504#endif
505 vty_out(vty, "service walltime-warning %lu\n",
ef78e4fd 506 walltime_threshold / 1000);
45f01188 507
0204baa8
DW
508 if (host.advanced)
509 vty_out(vty, "service advanced-vty\n");
d62a17ae 510
0204baa8
DW
511 if (host.encrypt)
512 vty_out(vty, "service password-encryption\n");
d62a17ae 513
0204baa8 514 if (host.lines >= 0)
3518f352
DS
515 vty_out(vty, "service terminal-length %d\n",
516 host.lines);
d62a17ae 517
0204baa8
DW
518 if (host.motdfile)
519 vty_out(vty, "banner motd file %s\n", host.motdfile);
19d61463
DA
520 else if (host.motd
521 && strncmp(host.motd, FRR_DEFAULT_MOTD,
522 strlen(host.motd)))
523 vty_out(vty, "banner motd line %s\n", host.motd);
0204baa8
DW
524 else if (!host.motd)
525 vty_out(vty, "no banner motd\n");
526 }
d62a17ae 527
9eed278b
DL
528 if (debug_memstats_at_exit)
529 vty_out(vty, "!\ndebug memstats-at-exit\n");
530
d62a17ae 531 return 1;
718e3744 532}
533
d0bfb22c 534/* Utility function for getting command graph. */
d62a17ae 535static struct graph *cmd_node_graph(vector v, enum node_type ntype)
718e3744 536{
d62a17ae 537 struct cmd_node *cnode = vector_slot(v, ntype);
0e06eb8b
DL
538
539 cmd_finalize_node(cnode);
d62a17ae 540 return cnode->cmdgraph;
718e3744 541}
542
d62a17ae 543static int cmd_try_do_shortcut(enum node_type node, char *first_word)
544{
545 if (first_word != NULL && node != AUTH_NODE && node != VIEW_NODE
546 && node != AUTH_ENABLE_NODE && 0 == strcmp("do", first_word))
547 return 1;
548 return 0;
718e3744 549}
550
d0bfb22c
QY
551/**
552 * Compare function for cmd_token.
553 * Used with qsort to sort command completions.
554 */
d62a17ae 555static int compare_completions(const void *fst, const void *snd)
718e3744 556{
36de6e0e
A
557 const struct cmd_token *first = *(const struct cmd_token * const *)fst,
558 *secnd = *(const struct cmd_token * const *)snd;
d62a17ae 559 return strcmp(first->text, secnd->text);
718e3744 560}
561
d0bfb22c
QY
562/**
563 * Takes a list of completions returned by command_complete,
564 * dedeuplicates them based on both text and description,
6011c1b2
QY
565 * sorts them, and returns them as a vector.
566 *
567 * @param completions linked list of cmd_token
568 * @return deduplicated and sorted vector with
d0bfb22c 569 */
d62a17ae 570vector completions_to_vec(struct list *completions)
571{
572 vector comps = vector_init(VECTOR_MIN_SIZE);
573
574 struct listnode *ln;
575 struct cmd_token *token, *cr = NULL;
576 unsigned int i, exists;
577 for (ALL_LIST_ELEMENTS_RO(completions, ln, token)) {
578 if (token->type == END_TKN && (cr = token))
579 continue;
580
581 // linear search for token in completions vector
582 exists = 0;
583 for (i = 0; i < vector_active(comps) && !exists; i++) {
584 struct cmd_token *curr = vector_slot(comps, i);
53205694 585#ifdef VTYSH_DEBUG
d62a17ae 586 exists = !strcmp(curr->text, token->text)
587 && !strcmp(curr->desc, token->desc);
53205694 588#else
d62a17ae 589 exists = !strcmp(curr->text, token->text);
53205694 590#endif /* VTYSH_DEBUG */
d62a17ae 591 }
909a2155 592
d62a17ae 593 if (!exists)
594 vector_set(comps, token);
595 }
cd40b329 596
d62a17ae 597 // sort completions
598 qsort(comps->index, vector_active(comps), sizeof(void *),
599 &compare_completions);
cd40b329 600
d62a17ae 601 // make <cr> the first element, if it is present
602 if (cr) {
603 vector_set_index(comps, vector_active(comps), NULL);
604 memmove(comps->index + 1, comps->index,
605 (comps->alloced - 1) * sizeof(void *));
606 vector_set_index(comps, 0, cr);
607 }
6011c1b2 608
d62a17ae 609 return comps;
cd40b329 610}
d0bfb22c
QY
611/**
612 * Generates a vector of cmd_token representing possible completions
613 * on the current input.
614 *
615 * @param vline the vectorized input line
616 * @param vty the vty with the node to match on
617 * @param status pointer to matcher status code
ebacb4ed 618 * @return vector of struct cmd_token * with possible completions
d0bfb22c 619 */
d62a17ae 620static vector cmd_complete_command_real(vector vline, struct vty *vty,
621 int *status)
cd40b329 622{
d62a17ae 623 struct list *completions;
624 struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
cd40b329 625
d62a17ae 626 enum matcher_rv rv = command_complete(cmdgraph, vline, &completions);
cd40b329 627
d62a17ae 628 if (MATCHER_ERROR(rv)) {
629 *status = CMD_ERR_NO_MATCH;
630 return NULL;
631 }
b92938a7 632
d62a17ae 633 vector comps = completions_to_vec(completions);
6a154c88 634 list_delete(&completions);
b92938a7 635
d62a17ae 636 // set status code appropriately
637 switch (vector_active(comps)) {
638 case 0:
639 *status = CMD_ERR_NO_MATCH;
640 break;
641 case 1:
642 *status = CMD_COMPLETE_FULL_MATCH;
643 break;
644 default:
645 *status = CMD_COMPLETE_LIST_MATCH;
646 }
718e3744 647
d62a17ae 648 return comps;
d0bfb22c 649}
718e3744 650
d62a17ae 651vector cmd_describe_command(vector vline, struct vty *vty, int *status)
d0bfb22c 652{
d62a17ae 653 vector ret;
718e3744 654
d62a17ae 655 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
656 enum node_type onode;
1c2facd1 657 int orig_xpath_index;
d62a17ae 658 vector shifted_vline;
659 unsigned int index;
718e3744 660
d62a17ae 661 onode = vty->node;
1c2facd1 662 orig_xpath_index = vty->xpath_index;
d62a17ae 663 vty->node = ENABLE_NODE;
1c2facd1 664 vty->xpath_index = 0;
d62a17ae 665 /* We can try it on enable node, cos' the vty is authenticated
666 */
718e3744 667
d62a17ae 668 shifted_vline = vector_init(vector_count(vline));
669 /* use memcpy? */
670 for (index = 1; index < vector_active(vline); index++) {
671 vector_set_index(shifted_vline, index - 1,
672 vector_lookup(vline, index));
673 }
718e3744 674
d62a17ae 675 ret = cmd_complete_command_real(shifted_vline, vty, status);
d0bfb22c 676
d62a17ae 677 vector_free(shifted_vline);
678 vty->node = onode;
1c2facd1 679 vty->xpath_index = orig_xpath_index;
d62a17ae 680 return ret;
681 }
718e3744 682
d62a17ae 683 return cmd_complete_command_real(vline, vty, status);
718e3744 684}
685
70d44c5c
DL
686static struct list *varhandlers = NULL;
687
d62a17ae 688void cmd_variable_complete(struct cmd_token *token, const char *arg,
689 vector comps)
690{
691 struct listnode *ln;
692 const struct cmd_variable_handler *cvh;
693 size_t i, argsz;
694 vector tmpcomps;
695
696 tmpcomps = arg ? vector_init(VECTOR_MIN_SIZE) : comps;
697
698 for (ALL_LIST_ELEMENTS_RO(varhandlers, ln, cvh)) {
699 if (cvh->tokenname && strcmp(cvh->tokenname, token->text))
700 continue;
9d303b37
DL
701 if (cvh->varname && (!token->varname
702 || strcmp(cvh->varname, token->varname)))
d62a17ae 703 continue;
704 cvh->completions(tmpcomps, token);
705 break;
706 }
707
708 if (!arg)
709 return;
710
711 argsz = strlen(arg);
712 for (i = vector_active(tmpcomps); i; i--) {
713 char *item = vector_slot(tmpcomps, i - 1);
714 if (strlen(item) >= argsz && !strncmp(item, arg, argsz))
715 vector_set(comps, item);
716 else
717 XFREE(MTYPE_COMPLETION, item);
718 }
719 vector_free(tmpcomps);
70d44c5c
DL
720}
721
1a0f614d
QY
722#define AUTOCOMP_INDENT 5
723
d62a17ae 724char *cmd_variable_comp2str(vector comps, unsigned short cols)
1a0f614d 725{
d62a17ae 726 size_t bsz = 16;
727 char *buf = XCALLOC(MTYPE_TMP, bsz);
728 int lc = AUTOCOMP_INDENT;
729 size_t cs = AUTOCOMP_INDENT;
730 size_t itemlen;
731 snprintf(buf, bsz, "%*s", AUTOCOMP_INDENT, "");
732 for (size_t j = 0; j < vector_active(comps); j++) {
733 char *item = vector_slot(comps, j);
734 itemlen = strlen(item);
1a0f614d 735
d62a17ae 736 if (cs + itemlen + AUTOCOMP_INDENT + 3 >= bsz)
737 buf = XREALLOC(MTYPE_TMP, buf, (bsz *= 2));
1a0f614d 738
d62a17ae 739 if (lc + itemlen + 1 >= cols) {
740 cs += snprintf(&buf[cs], bsz - cs, "\n%*s",
741 AUTOCOMP_INDENT, "");
742 lc = AUTOCOMP_INDENT;
743 }
1a0f614d 744
d62a17ae 745 size_t written = snprintf(&buf[cs], bsz - cs, "%s ", item);
746 lc += written;
747 cs += written;
748 XFREE(MTYPE_COMPLETION, item);
749 vector_set_index(comps, j, NULL);
750 }
751 return buf;
1a0f614d
QY
752}
753
d62a17ae 754void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
70d44c5c 755{
d62a17ae 756 if (!varhandlers)
757 return;
70d44c5c 758
d62a17ae 759 for (; cvh->completions; cvh++)
760 listnode_add(varhandlers, (void *)cvh);
70d44c5c
DL
761}
762
7f059ea6
DL
763DEFUN_HIDDEN (autocomplete,
764 autocomplete_cmd,
765 "autocomplete TYPE TEXT VARNAME",
766 "Autocompletion handler (internal, for vtysh)\n"
767 "cmd_token->type\n"
768 "cmd_token->text\n"
769 "cmd_token->varname\n")
770{
d62a17ae 771 struct cmd_token tok;
772 vector comps = vector_init(32);
773 size_t i;
7f059ea6 774
d62a17ae 775 memset(&tok, 0, sizeof(tok));
776 tok.type = atoi(argv[1]->arg);
777 tok.text = argv[2]->arg;
778 tok.varname = argv[3]->arg;
779 if (!strcmp(tok.varname, "-"))
780 tok.varname = NULL;
7f059ea6 781
d62a17ae 782 cmd_variable_complete(&tok, NULL, comps);
7f059ea6 783
d62a17ae 784 for (i = 0; i < vector_active(comps); i++) {
785 char *text = vector_slot(comps, i);
786 vty_out(vty, "%s\n", text);
787 XFREE(MTYPE_COMPLETION, text);
788 }
7f059ea6 789
d62a17ae 790 vector_free(comps);
791 return CMD_SUCCESS;
7f059ea6
DL
792}
793
ebacb4ed
QY
794/**
795 * Generate possible tab-completions for the given input. This function only
796 * returns results that would result in a valid command if used as Readline
797 * completions (as is the case in vtysh). For instance, if the passed vline ends
798 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
799 *
800 * @param vline vectorized input line
801 * @param vty the vty
802 * @param status location to store matcher status code in
803 * @return set of valid strings for use with Readline as tab-completions.
804 */
805
d62a17ae 806char **cmd_complete_command(vector vline, struct vty *vty, int *status)
807{
808 char **ret = NULL;
809 int original_node = vty->node;
810 vector input_line = vector_init(vector_count(vline));
811
812 // if the first token is 'do' we'll want to execute the command in the
813 // enable node
814 int do_shortcut = cmd_try_do_shortcut(vty->node, vector_slot(vline, 0));
815 vty->node = do_shortcut ? ENABLE_NODE : original_node;
816
817 // construct the input line we'll be matching on
818 unsigned int offset = (do_shortcut) ? 1 : 0;
819 for (unsigned index = 0; index + offset < vector_active(vline); index++)
820 vector_set_index(input_line, index,
821 vector_lookup(vline, index + offset));
822
823 // get token completions -- this is a copying operation
824 vector comps = NULL, initial_comps;
825 initial_comps = cmd_complete_command_real(input_line, vty, status);
826
827 if (!MATCHER_ERROR(*status)) {
828 assert(initial_comps);
829 // filter out everything that is not suitable for a
830 // tab-completion
831 comps = vector_init(VECTOR_MIN_SIZE);
832 for (unsigned int i = 0; i < vector_active(initial_comps);
833 i++) {
834 struct cmd_token *token = vector_slot(initial_comps, i);
835 if (token->type == WORD_TKN)
836 vector_set(comps, XSTRDUP(MTYPE_COMPLETION,
837 token->text));
838 else if (IS_VARYING_TOKEN(token->type)) {
839 const char *ref = vector_lookup(
840 vline, vector_active(vline) - 1);
841 cmd_variable_complete(token, ref, comps);
842 }
843 }
844 vector_free(initial_comps);
845
846 // since we filtered results, we need to re-set status code
847 switch (vector_active(comps)) {
848 case 0:
849 *status = CMD_ERR_NO_MATCH;
850 break;
851 case 1:
852 *status = CMD_COMPLETE_FULL_MATCH;
853 break;
854 default:
855 *status = CMD_COMPLETE_LIST_MATCH;
856 }
857
858 // copy completions text into an array of char*
859 ret = XMALLOC(MTYPE_TMP,
860 (vector_active(comps) + 1) * sizeof(char *));
861 unsigned int i;
862 for (i = 0; i < vector_active(comps); i++) {
863 ret[i] = vector_slot(comps, i);
864 }
865 // set the last element to NULL, because this array is used in
866 // a Readline completion_generator function which expects NULL
867 // as a sentinel value
868 ret[i] = NULL;
869 vector_free(comps);
870 comps = NULL;
871 } else if (initial_comps)
872 vector_free(initial_comps);
873
874 // comps should always be null here
875 assert(!comps);
876
877 // free the adjusted input line
878 vector_free(input_line);
879
880 // reset vty->node to its original value
881 vty->node = original_node;
882
883 return ret;
cde9f101 884}
b92938a7 885
b92938a7 886/* return parent node */
887/* MUST eventually converge on CONFIG_NODE */
d62a17ae 888enum node_type node_parent(enum node_type node)
889{
c1e7a5e4 890 struct cmd_node *cnode;
d62a17ae 891
892 assert(node > CONFIG_NODE);
893
c1e7a5e4 894 cnode = vector_lookup(cmdvec, node);
d62a17ae 895
c1e7a5e4 896 return cnode->parent_node;
b92938a7 897}
898
718e3744 899/* Execute command by argument vline vector. */
c139972c 900static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
d62a17ae 901 struct vty *vty,
e3476061
DL
902 const struct cmd_element **cmd,
903 unsigned int up_level)
d62a17ae 904{
905 struct list *argv_list;
906 enum matcher_rv status;
907 const struct cmd_element *matched_element = NULL;
e3476061
DL
908 unsigned int i;
909 int xpath_index = vty->xpath_index;
910 int node = vty->node;
d62a17ae 911
e3476061
DL
912 /* only happens for legacy split config file load; need to check for
913 * a match before calling node_exit handlers below
914 */
915 for (i = 0; i < up_level; i++) {
dd2c81b8
DL
916 struct cmd_node *cnode;
917
e3476061
DL
918 if (node <= CONFIG_NODE)
919 return CMD_NO_LEVEL_UP;
920
dd2c81b8 921 cnode = vector_slot(cmdvec, node);
e3476061
DL
922 node = node_parent(node);
923
dd2c81b8 924 if (xpath_index > 0 && !cnode->no_xpath)
e3476061
DL
925 xpath_index--;
926 }
927
928 struct graph *cmdgraph = cmd_node_graph(cmdvec, node);
d62a17ae 929 status = command_match(cmdgraph, vline, &argv_list, &matched_element);
930
931 if (cmd)
932 *cmd = matched_element;
933
934 // if matcher error, return corresponding CMD_ERR
935 if (MATCHER_ERROR(status)) {
936 if (argv_list)
6a154c88 937 list_delete(&argv_list);
d62a17ae 938 switch (status) {
939 case MATCHER_INCOMPLETE:
940 return CMD_ERR_INCOMPLETE;
941 case MATCHER_AMBIGUOUS:
942 return CMD_ERR_AMBIGUOUS;
bde30e78
DS
943 case MATCHER_NO_MATCH:
944 case MATCHER_OK:
d62a17ae 945 return CMD_ERR_NO_MATCH;
946 }
947 }
948
e3476061
DL
949 for (i = 0; i < up_level; i++)
950 cmd_exit(vty);
951
d62a17ae 952 // build argv array from argv list
953 struct cmd_token **argv = XMALLOC(
954 MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
955 struct listnode *ln;
956 struct cmd_token *token;
e3476061
DL
957
958 i = 0;
d62a17ae 959 for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
960 argv[i++] = token;
961
962 int argc = argv_list->count;
963
964 int ret;
965 if (matched_element->daemon)
966 ret = CMD_SUCCESS_DAEMON;
a6233bfc 967 else {
eaf6705d
RW
968 if (vty->config) {
969 /* Clear array of enqueued configuration changes. */
970 vty->num_cfg_changes = 0;
971 memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
972
689b9cf5
RW
973 /* Regenerate candidate configuration if necessary. */
974 if (frr_get_cli_mode() == FRR_CLI_CLASSIC
975 && running_config->version
976 > vty->candidate_config->version)
eaf6705d
RW
977 nb_config_replace(vty->candidate_config,
978 running_config, true);
b855e95f
RW
979
980 /*
981 * Perform pending commit (if any) before executing
982 * non-YANG command.
983 */
9eebf97e 984 if (!(matched_element->attr & CMD_ATTR_YANG))
fd396924 985 (void)nb_cli_pending_commit_check(vty);
eaf6705d 986 }
a6233bfc 987
d62a17ae 988 ret = matched_element->func(matched_element, vty, argc, argv);
a6233bfc 989 }
d62a17ae 990
991 // delete list and cmd_token's in it
6a154c88 992 list_delete(&argv_list);
d62a17ae 993 XFREE(MTYPE_TMP, argv);
994
995 return ret;
718e3744 996}
997
cd40b329
CF
998/**
999 * Execute a given command, handling things like "do ..." and checking
1000 * whether the given command might apply at a parent node if doesn't
1001 * apply for the current node.
1002 *
1003 * @param vline Command line input, vector of char* where each element is
1004 * one input token.
1005 * @param vty The vty context in which the command should be executed.
1006 * @param cmd Pointer where the struct cmd_element of the matched command
1007 * will be stored, if any. May be set to NULL if this info is
1008 * not needed.
1009 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1010 * @return The status of the command that has been executed or an error code
1011 * as to why no command could be executed.
1012 */
d62a17ae 1013int cmd_execute_command(vector vline, struct vty *vty,
1014 const struct cmd_element **cmd, int vtysh)
17aca20b 1015{
d62a17ae 1016 int ret, saved_ret = 0;
1017 enum node_type onode, try_node;
1c2facd1 1018 int orig_xpath_index;
eda031f6 1019
d62a17ae 1020 onode = try_node = vty->node;
1c2facd1 1021 orig_xpath_index = vty->xpath_index;
b92938a7 1022
d62a17ae 1023 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1024 vector shifted_vline;
1025 unsigned int index;
b92938a7 1026
d62a17ae 1027 vty->node = ENABLE_NODE;
1c2facd1 1028 vty->xpath_index = 0;
d62a17ae 1029 /* We can try it on enable node, cos' the vty is authenticated
1030 */
b92938a7 1031
d62a17ae 1032 shifted_vline = vector_init(vector_count(vline));
1033 /* use memcpy? */
1034 for (index = 1; index < vector_active(vline); index++)
1035 vector_set_index(shifted_vline, index - 1,
1036 vector_lookup(vline, index));
b92938a7 1037
d62a17ae 1038 ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
e3476061 1039 vty, cmd, 0);
b92938a7 1040
d62a17ae 1041 vector_free(shifted_vline);
1042 vty->node = onode;
1c2facd1 1043 vty->xpath_index = orig_xpath_index;
d62a17ae 1044 return ret;
1045 }
b92938a7 1046
d62a17ae 1047 saved_ret = ret =
e3476061 1048 cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0);
b92938a7 1049
d62a17ae 1050 if (vtysh)
1051 return saved_ret;
87d683b0 1052
825d5fbf 1053 if (ret != CMD_SUCCESS && ret != CMD_WARNING
4bb7f7c2 1054 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
825d5fbf 1055 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
d62a17ae 1056 /* This assumes all nodes above CONFIG_NODE are childs of
1057 * CONFIG_NODE */
1058 while (vty->node > CONFIG_NODE) {
dd2c81b8
DL
1059 struct cmd_node *cnode = vector_slot(cmdvec, try_node);
1060
d62a17ae 1061 try_node = node_parent(try_node);
1062 vty->node = try_node;
dd2c81b8 1063 if (vty->xpath_index > 0 && !cnode->no_xpath)
1c2facd1 1064 vty->xpath_index--;
dd2c81b8 1065
d62a17ae 1066 ret = cmd_execute_command_real(vline, FILTER_RELAXED,
e3476061 1067 vty, cmd, 0);
825d5fbf 1068 if (ret == CMD_SUCCESS || ret == CMD_WARNING
4bb7f7c2 1069 || ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE
825d5fbf
CS
1070 || ret == CMD_NOT_MY_INSTANCE
1071 || ret == CMD_WARNING_CONFIG_FAILED)
d62a17ae 1072 return ret;
1073 }
1074 /* no command succeeded, reset the vty to the original node */
1075 vty->node = onode;
1c2facd1 1076 vty->xpath_index = orig_xpath_index;
d62a17ae 1077 }
04e64062 1078
d62a17ae 1079 /* return command status for original node */
1080 return saved_ret;
b92938a7 1081}
1082
cd40b329
CF
1083/**
1084 * Execute a given command, matching it strictly against the current node.
1085 * This mode is used when reading config files.
1086 *
1087 * @param vline Command line input, vector of char* where each element is
1088 * one input token.
1089 * @param vty The vty context in which the command should be executed.
1090 * @param cmd Pointer where the struct cmd_element* of the matched command
1091 * will be stored, if any. May be set to NULL if this info is
1092 * not needed.
1093 * @return The status of the command that has been executed or an error code
1094 * as to why no command could be executed.
1095 */
d62a17ae 1096int cmd_execute_command_strict(vector vline, struct vty *vty,
1097 const struct cmd_element **cmd)
718e3744 1098{
e3476061 1099 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd, 0);
718e3744 1100}
1101
01e24c4a
QY
1102/*
1103 * Hook for preprocessing command string before executing.
1104 *
1105 * All subscribers are called with the raw command string that is to be
1106 * executed. If any changes are to be made, a new string should be allocated
1107 * with MTYPE_TMP and *cmd_out updated to point to this new string. The caller
1108 * is then responsible for freeing this string.
1109 *
1110 * All processing functions must be mutually exclusive in their action, i.e. if
1111 * one subscriber decides to modify the command, all others must not modify it
1112 * when called. Feeding the output of one processing command into a subsequent
1113 * one is not supported.
1114 *
1115 * This hook is intentionally internal to the command processing system.
1116 *
1117 * cmd_in
1118 * The raw command string.
1119 *
1120 * cmd_out
1121 * The result of any processing.
1122 */
1123DECLARE_HOOK(cmd_execute,
0a334343 1124 (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a 1125 (vty, cmd_in, cmd_out));
0a334343 1126DEFINE_HOOK(cmd_execute, (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a
QY
1127 (vty, cmd_in, cmd_out));
1128
1129/* Hook executed after a CLI command. */
0a334343 1130DECLARE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a 1131 (vty, cmd_exec));
0a334343 1132DEFINE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a
QY
1133 (vty, cmd_exec));
1134
fe6b47b9
QY
1135/*
1136 * cmd_execute hook subscriber to handle `|` actions.
1137 */
1138static int handle_pipe_action(struct vty *vty, const char *cmd_in,
1139 char **cmd_out)
1140{
1141 /* look for `|` */
9f227e4c 1142 char *orig, *working, *token, *u;
fe6b47b9 1143 char *pipe = strstr(cmd_in, "| ");
2f272cb4 1144 int ret = 0;
fe6b47b9
QY
1145
1146 if (!pipe)
1147 return 0;
1148
1149 /* duplicate string for processing purposes, not including pipe */
1150 orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
1151
1152 /* retrieve action */
1153 token = strsep(&working, " ");
4f4060f6 1154 assert(token);
fe6b47b9
QY
1155
1156 /* match result to known actions */
1157 if (strmatch(token, "include")) {
1158 /* the remaining text should be a regexp */
1159 char *regexp = working;
5d806ec6
QY
1160
1161 if (!regexp) {
1162 vty_out(vty, "%% Need a regexp to filter with\n");
2f272cb4 1163 ret = 1;
5d806ec6
QY
1164 goto fail;
1165 }
1166
fe6b47b9 1167 bool succ = vty_set_include(vty, regexp);
0a334343 1168
fe6b47b9 1169 if (!succ) {
5d806ec6 1170 vty_out(vty, "%% Bad regexp '%s'\n", regexp);
2f272cb4 1171 ret = 1;
fe6b47b9
QY
1172 goto fail;
1173 }
2cddf2ff 1174 *cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
9f227e4c 1175 u = *cmd_out;
1176 strsep(&u, "|");
fe6b47b9 1177 } else {
5d806ec6 1178 vty_out(vty, "%% Unknown action '%s'\n", token);
2f272cb4 1179 ret = 1;
fe6b47b9
QY
1180 goto fail;
1181 }
1182
1183fail:
1184 XFREE(MTYPE_TMP, orig);
2f272cb4 1185 return ret;
fe6b47b9
QY
1186}
1187
1188static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
1189{
0b42d81a 1190 if (vty->filter)
fe6b47b9 1191 vty_set_include(vty, NULL);
0b42d81a 1192
fe6b47b9
QY
1193 return 0;
1194}
1195
01e24c4a
QY
1196int cmd_execute(struct vty *vty, const char *cmd,
1197 const struct cmd_element **matched, int vtysh)
1198{
1199 int ret;
1200 char *cmd_out = NULL;
2f272cb4 1201 const char *cmd_exec = NULL;
01e24c4a
QY
1202 vector vline;
1203
2f272cb4
IR
1204 ret = hook_call(cmd_execute, vty, cmd, &cmd_out);
1205 if (ret) {
1206 ret = CMD_WARNING;
1207 goto free;
1208 }
1209
01e24c4a
QY
1210 cmd_exec = cmd_out ? (const char *)cmd_out : cmd;
1211
1212 vline = cmd_make_strvec(cmd_exec);
1213
1214 if (vline) {
1215 ret = cmd_execute_command(vline, vty, matched, vtysh);
1216 cmd_free_strvec(vline);
1217 } else {
1218 ret = CMD_SUCCESS;
1219 }
1220
2f272cb4 1221free:
01e24c4a
QY
1222 hook_call(cmd_execute_done, vty, cmd_exec);
1223
0a22ddfb 1224 XFREE(MTYPE_TMP, cmd_out);
01e24c4a
QY
1225
1226 return ret;
1227}
1228
1229
bed578b8 1230/**
d62a17ae 1231 * Parse one line of config, walking up the parse tree attempting to find a
1232 * match
bed578b8
DS
1233 *
1234 * @param vty The vty context in which the command should be executed.
1235 * @param cmd Pointer where the struct cmd_element* of the match command
1236 * will be stored, if any. May be set to NULL if this info is
1237 * not needed.
d62a17ae 1238 * @param use_daemon Boolean to control whether or not we match on
1239 * CMD_SUCCESS_DAEMON
bed578b8
DS
1240 * or not.
1241 * @return The status of the command that has been executed or an error code
1242 * as to why no command could be executed.
1243 */
d62a17ae 1244int command_config_read_one_line(struct vty *vty,
7ab57d19
DS
1245 const struct cmd_element **cmd,
1246 uint32_t line_num, int use_daemon)
bed578b8 1247{
d62a17ae 1248 vector vline;
d62a17ae 1249 int ret;
e3476061 1250 unsigned up_level = 0;
bed578b8 1251
d62a17ae 1252 vline = cmd_make_strvec(vty->buf);
bed578b8 1253
d62a17ae 1254 /* In case of comment line */
1255 if (vline == NULL)
1256 return CMD_SUCCESS;
bed578b8 1257
d62a17ae 1258 /* Execute configuration command : this is strict match */
1259 ret = cmd_execute_command_strict(vline, vty, cmd);
bed578b8 1260
e3476061
DL
1261 /* The logic for trying parent nodes is in cmd_execute_command_real()
1262 * since calling ->node_exit() correctly is a bit involved. This is
1263 * also the only reason CMD_NO_LEVEL_UP exists.
1264 */
1265 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1266 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1267 && ret != CMD_SUCCESS && ret != CMD_WARNING
4bb7f7c2 1268 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
e3476061
DL
1269 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
1270 && ret != CMD_NO_LEVEL_UP)
1271 ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
1272 ++up_level);
1273
1274 if (ret == CMD_NO_LEVEL_UP)
1275 ret = CMD_ERR_NO_MATCH;
bed578b8 1276
b45d8ccc
DS
1277 if (ret != CMD_SUCCESS &&
1278 ret != CMD_WARNING &&
1279 ret != CMD_SUCCESS_DAEMON) {
7ab57d19
DS
1280 struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve));
1281
1282 memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
1283 ve->line_num = line_num;
1284 if (!vty->error)
1285 vty->error = list_new();
1286
1287 listnode_add(vty->error, ve);
1288 }
cbd7259d 1289
d62a17ae 1290 cmd_free_strvec(vline);
bed578b8 1291
d62a17ae 1292 return ret;
bed578b8
DS
1293}
1294
5689fe5f 1295/* Configuration make from file. */
d62a17ae 1296int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 1297{
d62a17ae 1298 int ret, error_ret = 0;
1299 *line_num = 0;
718e3744 1300
d62a17ae 1301 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
7ab57d19 1302 ++(*line_num);
13fbc82d 1303
7ab57d19 1304 ret = command_config_read_one_line(vty, NULL, *line_num, 0);
718e3744 1305
d62a17ae 1306 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1307 && ret != CMD_ERR_NOTHING_TODO)
1308 error_ret = ret;
1309 }
5689fe5f 1310
d62a17ae 1311 if (error_ret) {
1312 return error_ret;
1313 }
5689fe5f 1314
d62a17ae 1315 return CMD_SUCCESS;
718e3744 1316}
1317
5689fe5f 1318/* Configuration from terminal */
718e3744 1319DEFUN (config_terminal,
1320 config_terminal_cmd,
dc1c13c0 1321 "configure [terminal]",
718e3744 1322 "Configuration from vty interface\n"
1323 "Configuration terminal\n")
1324{
f344c66e 1325 return vty_config_enter(vty, false, false);
718e3744 1326}
1327
1328/* Enable command */
d0bfb22c 1329DEFUN (enable,
718e3744 1330 config_enable_cmd,
1331 "enable",
1332 "Turn on privileged mode command\n")
1333{
d62a17ae 1334 /* If enable password is NULL, change to ENABLE_NODE */
1335 if ((host.enable == NULL && host.enable_encrypt == NULL)
1336 || vty->type == VTY_SHELL_SERV)
1337 vty->node = ENABLE_NODE;
1338 else
1339 vty->node = AUTH_ENABLE_NODE;
718e3744 1340
d62a17ae 1341 return CMD_SUCCESS;
718e3744 1342}
1343
1344/* Disable command */
d0bfb22c 1345DEFUN (disable,
718e3744 1346 config_disable_cmd,
1347 "disable",
1348 "Turn off privileged mode command\n")
1349{
d62a17ae 1350 if (vty->node == ENABLE_NODE)
1351 vty->node = VIEW_NODE;
1352 return CMD_SUCCESS;
718e3744 1353}
1354
1355/* Down vty node level. */
1356DEFUN (config_exit,
1357 config_exit_cmd,
1358 "exit",
1359 "Exit current mode and down to previous mode\n")
0b84f294 1360{
d62a17ae 1361 cmd_exit(vty);
1362 return CMD_SUCCESS;
1363}
1364
791ded4a
DL
1365static int root_on_exit(struct vty *vty)
1366{
1367 if (vty_shell(vty))
1368 exit(0);
1369 else
1370 vty->status = VTY_CLOSE;
1371 return 0;
1372}
1373
d62a17ae 1374void cmd_exit(struct vty *vty)
1375{
24389580 1376 struct cmd_node *cnode = vector_lookup(cmdvec, vty->node);
1c2facd1 1377
791ded4a
DL
1378 if (cnode->node_exit) {
1379 if (!cnode->node_exit(vty))
1380 return;
d62a17ae 1381 }
791ded4a
DL
1382 if (cnode->parent_node)
1383 vty->node = cnode->parent_node;
dd2c81b8 1384 if (vty->xpath_index > 0 && !cnode->no_xpath)
1c2facd1 1385 vty->xpath_index--;
718e3744 1386}
1387
f667a580
QY
1388/* ALIAS_FIXME */
1389DEFUN (config_quit,
1390 config_quit_cmd,
1391 "quit",
1392 "Exit current mode and down to previous mode\n")
1393{
d62a17ae 1394 return config_exit(self, vty, argc, argv);
f667a580
QY
1395}
1396
d0bfb22c 1397
718e3744 1398/* End of configuration. */
1399DEFUN (config_end,
1400 config_end_cmd,
1401 "end",
efd7904e 1402 "End current mode and change to enable mode.\n")
718e3744 1403{
cf09d3ca 1404 if (vty->config) {
f344c66e 1405 vty_config_exit(vty);
d62a17ae 1406 vty->node = ENABLE_NODE;
d62a17ae 1407 }
1408 return CMD_SUCCESS;
718e3744 1409}
1410
1411/* Show version. */
1412DEFUN (show_version,
1413 show_version_cmd,
1414 "show version",
1415 SHOW_STR
1416 "Displays zebra version\n")
1417{
46b48b33
DS
1418 vty_out(vty, "%s %s (%s) on %s(%s).\n", FRR_FULL_NAME, FRR_VERSION,
1419 cmd_hostname_get() ? cmd_hostname_get() : "", cmd_system_get(),
1420 cmd_release_get());
d62a17ae 1421 vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
e063f271 1422#ifdef ENABLE_VERSION_BUILD_CONFIG
d62a17ae 1423 vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
e063f271 1424#endif
d62a17ae 1425 return CMD_SUCCESS;
718e3744 1426}
1427
1428/* Help display function for all node. */
1429DEFUN (config_help,
1430 config_help_cmd,
1431 "help",
1432 "Description of the interactive help system\n")
1433{
d62a17ae 1434 vty_out(vty,
1435 "Quagga VTY provides advanced help feature. When you need help,\n\
61b7d449
DL
1436anytime at the command line please press '?'.\n\
1437\n\
1438If nothing matches, the help list will be empty and you must backup\n\
1439 until entering a '?' shows the available options.\n\
1440Two styles of help are provided:\n\
14411. Full help is available when you are ready to enter a\n\
1442command argument (e.g. 'show ?') and describes each possible\n\
1443argument.\n\
14442. Partial help is provided when an abbreviated argument is entered\n\
1445 and you want to know what arguments match the input\n\
1446 (e.g. 'show me?'.)\n\n");
d62a17ae 1447 return CMD_SUCCESS;
1448}
1449
1450static void permute(struct graph_node *start, struct vty *vty)
1451{
1452 static struct list *position = NULL;
1453 if (!position)
1454 position = list_new();
1455
1456 struct cmd_token *stok = start->data;
1457 struct graph_node *gnn;
1458 struct listnode *ln;
1459
1460 // recursive dfs
1461 listnode_add(position, start);
1462 for (unsigned int i = 0; i < vector_active(start->to); i++) {
1463 struct graph_node *gn = vector_slot(start->to, i);
1464 struct cmd_token *tok = gn->data;
9eebf97e 1465 if (tok->attr & CMD_ATTR_HIDDEN)
d62a17ae 1466 continue;
1467 else if (tok->type == END_TKN || gn == start) {
1468 vty_out(vty, " ");
1469 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
1470 struct cmd_token *tt = gnn->data;
1471 if (tt->type < SPECIAL_TKN)
1472 vty_out(vty, " %s", tt->text);
1473 }
1474 if (gn == start)
1475 vty_out(vty, "...");
1476 vty_out(vty, "\n");
1477 } else {
1478 bool skip = false;
1479 if (stok->type == FORK_TKN && tok->type != FORK_TKN)
1480 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
1481 if (gnn == gn) {
1482 skip = true;
1483 break;
1484 }
1485 if (!skip)
1486 permute(gn, vty);
1487 }
1488 }
1489 list_delete_node(position, listtail(position));
1490}
1491
5b96d81c
IR
1492static void print_cmd(struct vty *vty, const char *cmd)
1493{
1494 int i, j, len = strlen(cmd);
77af3a34 1495 char buf[len + 1];
5b96d81c
IR
1496 bool skip = false;
1497
1498 j = 0;
1499 for (i = 0; i < len; i++) {
1500 /* skip varname */
1501 if (cmd[i] == '$')
1502 skip = true;
1503 else if (strchr(" ()<>[]{}|", cmd[i]))
1504 skip = false;
1505
1506 if (skip)
1507 continue;
1508
1509 if (isspace(cmd[i])) {
1510 /* skip leading whitespace */
1511 if (i == 0)
1512 continue;
1513 /* skip trailing whitespace */
1514 if (i == len - 1)
1515 continue;
1516 /* skip all whitespace after opening brackets or pipe */
1517 if (strchr("(<[{|", cmd[i - 1])) {
1518 while (isspace(cmd[i + 1]))
1519 i++;
1520 continue;
1521 }
1522 /* skip repeated whitespace */
1523 if (isspace(cmd[i + 1]))
1524 continue;
1525 /* skip whitespace before closing brackets or pipe */
1526 if (strchr(")>]}|", cmd[i + 1]))
1527 continue;
1528 /* convert tabs to spaces */
1529 if (cmd[i] == '\t') {
1530 buf[j++] = ' ';
1531 continue;
1532 }
1533 }
1534
1535 buf[j++] = cmd[i];
1536 }
1537 buf[j] = 0;
1538
1539 vty_out(vty, "%s\n", buf);
1540}
1541
d62a17ae 1542int cmd_list_cmds(struct vty *vty, int do_permute)
1543{
1544 struct cmd_node *node = vector_slot(cmdvec, vty->node);
1545
0e06eb8b
DL
1546 if (do_permute) {
1547 cmd_finalize_node(node);
d62a17ae 1548 permute(vector_slot(node->cmdgraph->nodes, 0), vty);
0e06eb8b 1549 } else {
d62a17ae 1550 /* loop over all commands at this node */
154e9ca1 1551 const struct cmd_element *element = NULL;
d62a17ae 1552 for (unsigned int i = 0; i < vector_active(node->cmd_vector);
1553 i++)
9eebf97e
DL
1554 if ((element = vector_slot(node->cmd_vector, i)) &&
1555 !(element->attr & CMD_ATTR_HIDDEN)) {
5b96d81c
IR
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)
4d4c404b 2242 vty_out(vty, "%s does not exist\n", filename);
d62a17ae 2243 else if (cmd == CMD_WARNING_CONFIG_FAILED)
4d4c404b 2244 vty_out(vty, "%s must be in %s\n", 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
ac156aec
DA
2294DEFUN(allow_reserved_ranges, allow_reserved_ranges_cmd, "allow-reserved-ranges",
2295 "Allow using IPv4 (Class E) reserved IP space\n")
2296{
2297 host.allow_reserved_ranges = true;
2298 return CMD_SUCCESS;
2299}
2300
2301DEFUN(no_allow_reserved_ranges, no_allow_reserved_ranges_cmd,
2302 "no allow-reserved-ranges",
2303 NO_STR "Allow using IPv4 (Class E) reserved IP space\n")
2304{
2305 host.allow_reserved_ranges = false;
2306 return CMD_SUCCESS;
2307}
2308
c2278962 2309int cmd_find_cmds(struct vty *vty, struct cmd_token **argv, int argc)
a83a5331 2310{
cf6c83e7
QY
2311 const struct cmd_node *node;
2312 const struct cmd_element *cli;
2313 vector clis;
a83a5331 2314
68912a20
QY
2315 regex_t exp = {};
2316
767f67a4 2317 char *pattern = argv_concat(argv, argc, 1);
68912a20 2318 int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
767f67a4 2319 XFREE(MTYPE_TMP, pattern);
68912a20
QY
2320
2321 if (cr != 0) {
2322 switch (cr) {
2323 case REG_BADBR:
2324 vty_out(vty, "%% Invalid {...} expression\n");
2325 break;
2326 case REG_BADRPT:
2327 vty_out(vty, "%% Bad repetition operator\n");
2328 break;
2329 case REG_BADPAT:
2330 vty_out(vty, "%% Regex syntax error\n");
2331 break;
2332 case REG_ECOLLATE:
2333 vty_out(vty, "%% Invalid collating element\n");
2334 break;
2335 case REG_ECTYPE:
2336 vty_out(vty, "%% Invalid character class name\n");
2337 break;
2338 case REG_EESCAPE:
2339 vty_out(vty,
2340 "%% Regex ended with escape character (\\)\n");
2341 break;
2342 case REG_ESUBREG:
2343 vty_out(vty,
2344 "%% Invalid number in \\digit construction\n");
2345 break;
2346 case REG_EBRACK:
2347 vty_out(vty, "%% Unbalanced square brackets\n");
2348 break;
2349 case REG_EPAREN:
2350 vty_out(vty, "%% Unbalanced parentheses\n");
2351 break;
2352 case REG_EBRACE:
2353 vty_out(vty, "%% Unbalanced braces\n");
2354 break;
2355 case REG_ERANGE:
2356 vty_out(vty,
2357 "%% Invalid endpoint in range expression\n");
2358 break;
2359 case REG_ESPACE:
2360 vty_out(vty, "%% Failed to compile (out of memory)\n");
2361 break;
2362 }
2363
2364 goto done;
2365 }
2366
2367
a83a5331 2368 for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
cf6c83e7 2369 node = vector_slot(cmdvec, i);
a83a5331
QY
2370 if (!node)
2371 continue;
cf6c83e7 2372 clis = node->cmd_vector;
a83a5331 2373 for (unsigned int j = 0; j < vector_active(clis); j++) {
cf6c83e7 2374 cli = vector_slot(clis, j);
68912a20 2375
5b96d81c
IR
2376 if (regexec(&exp, cli->string, 0, NULL, 0) == 0) {
2377 vty_out(vty, " (%s) ", node->name);
2378 print_cmd(vty, cli->string);
2379 }
a83a5331
QY
2380 }
2381 }
2382
68912a20
QY
2383done:
2384 regfree(&exp);
a83a5331
QY
2385 return CMD_SUCCESS;
2386}
2387
c2278962
IR
2388DEFUN(find,
2389 find_cmd,
2390 "find REGEX...",
2391 "Find CLI command matching a regular expression\n"
2392 "Search pattern (POSIX regex)\n")
2393{
2394 return cmd_find_cmds(vty, argv, argc);
2395}
2396
fa22080d 2397#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
8be973f5
DL
2398DEFUN(script, script_cmd, "script SCRIPT FUNCTION",
2399 "Test command - execute a function in a script\n"
2400 "Script name (same as filename in /etc/frr/scripts/)\n"
2401 "Function name (in the script)\n")
5f98c815 2402{
3d19ffc5 2403 struct prefix p;
45e56ec4
DS
2404
2405 (void)str2prefix("1.2.3.4/24", &p);
a71096fb 2406 struct frrscript *fs = frrscript_new(argv[1]->arg);
5f98c815 2407
596b44af
DL
2408 if (frrscript_load(fs, argv[2]->arg, NULL)) {
2409 vty_out(vty,
8be973f5 2410 "/etc/frr/scripts/%s.lua or function '%s' not found\n",
596b44af 2411 argv[1]->arg, argv[2]->arg);
3d19ffc5 2412 }
5f98c815 2413
a71096fb
DL
2414 int ret = frrscript_call(fs, argv[2]->arg, ("p", &p));
2415 char buf[40];
2416 prefix2str(&p, buf, sizeof(buf));
2417 vty_out(vty, "p: %s\n", buf);
2418 vty_out(vty, "Script result: %d\n", ret);
5f98c815 2419
64d457d7 2420 frrscript_delete(fs);
ad6e9b85 2421
5f98c815
QY
2422 return CMD_SUCCESS;
2423}
2424#endif
2425
718e3744 2426/* Set config filename. Called from vty.c */
d62a17ae 2427void host_config_set(const char *filename)
718e3744 2428{
0a22ddfb 2429 XFREE(MTYPE_HOST, host.config);
d62a17ae 2430 host.config = XSTRDUP(MTYPE_HOST, filename);
718e3744 2431}
2432
d62a17ae 2433const char *host_config_get(void)
57387fb2 2434{
d62a17ae 2435 return host.config;
57387fb2
CF
2436}
2437
cf00164b
DS
2438void cmd_show_lib_debugs(struct vty *vty)
2439{
2440 route_map_show_debug(vty);
2441}
2442
d62a17ae 2443void install_default(enum node_type node)
718e3744 2444{
01485adb
DL
2445 _install_element(node, &config_exit_cmd);
2446 _install_element(node, &config_quit_cmd);
2447 _install_element(node, &config_end_cmd);
2448 _install_element(node, &config_help_cmd);
2449 _install_element(node, &config_list_cmd);
2450 _install_element(node, &show_cli_graph_cmd);
2451 _install_element(node, &find_cmd);
718e3744 2452
01485adb
DL
2453 _install_element(node, &config_write_cmd);
2454 _install_element(node, &show_running_config_cmd);
7f059ea6 2455
01485adb 2456 _install_element(node, &autocomplete_cmd);
1c2facd1
RW
2457
2458 nb_cli_install_default(node);
718e3744 2459}
2460
87f44e2f
DL
2461/* Initialize command interface. Install basic nodes and commands.
2462 *
2463 * terminal = 0 -- vtysh / no logging, no config control
2464 * terminal = 1 -- normal daemon
9473e340 2465 * terminal = -1 -- watchfrr / no logging, but minimal config control */
d62a17ae 2466void cmd_init(int terminal)
2467{
419cd5a0
MK
2468 struct utsname names;
2469
419cd5a0 2470 uname(&names);
d62a17ae 2471 qobj_init();
2472
fe6b47b9
QY
2473 /* register command preprocessors */
2474 hook_register(cmd_execute, handle_pipe_action);
2475 hook_register(cmd_execute_done, handle_pipe_action_done);
2476
d62a17ae 2477 varhandlers = list_new();
2478
2479 /* Allocate initial top vector of commands. */
2480 cmdvec = vector_init(VECTOR_MIN_SIZE);
2481
2482 /* Default host value settings. */
419cd5a0 2483 host.name = XSTRDUP(MTYPE_HOST, names.nodename);
46b48b33
DS
2484 host.system = XSTRDUP(MTYPE_HOST, names.sysname);
2485 host.release = XSTRDUP(MTYPE_HOST, names.release);
2486 host.version = XSTRDUP(MTYPE_HOST, names.version);
2487
419cd5a0 2488#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
6b3ee3a0
MK
2489 if ((strcmp(names.domainname, "(none)") == 0))
2490 host.domainname = NULL;
2491 else
2492 host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
419cd5a0
MK
2493#else
2494 host.domainname = NULL;
2495#endif
d62a17ae 2496 host.password = NULL;
2497 host.enable = NULL;
d62a17ae 2498 host.config = NULL;
2499 host.noconfig = (terminal < 0);
2500 host.lines = -1;
19d61463 2501 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2502 host.motdfile = NULL;
ac156aec 2503 host.allow_reserved_ranges = false;
d62a17ae 2504
2505 /* Install top nodes. */
612c2c15
DL
2506 install_node(&view_node);
2507 install_node(&enable_node);
2508 install_node(&auth_node);
2509 install_node(&auth_enable_node);
2510 install_node(&config_node);
d62a17ae 2511
2512 /* Each node's basic commands. */
2513 install_element(VIEW_NODE, &show_version_cmd);
a83a5331
QY
2514 install_element(ENABLE_NODE, &show_startup_config_cmd);
2515
d62a17ae 2516 if (terminal) {
85a6806d
MS
2517 install_element(ENABLE_NODE, &debug_memstats_cmd);
2518
d62a17ae 2519 install_element(VIEW_NODE, &config_list_cmd);
2520 install_element(VIEW_NODE, &config_exit_cmd);
2521 install_element(VIEW_NODE, &config_quit_cmd);
2522 install_element(VIEW_NODE, &config_help_cmd);
2523 install_element(VIEW_NODE, &config_enable_cmd);
2524 install_element(VIEW_NODE, &config_terminal_length_cmd);
2525 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
d62a17ae 2526 install_element(VIEW_NODE, &show_commandtree_cmd);
2527 install_element(VIEW_NODE, &echo_cmd);
2528 install_element(VIEW_NODE, &autocomplete_cmd);
a83a5331 2529 install_element(VIEW_NODE, &find_cmd);
fa22080d 2530#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
3d19ffc5
QY
2531 install_element(VIEW_NODE, &script_cmd);
2532#endif
2533
d62a17ae 2534
d62a17ae 2535 install_element(ENABLE_NODE, &config_end_cmd);
2536 install_element(ENABLE_NODE, &config_disable_cmd);
2537 install_element(ENABLE_NODE, &config_terminal_cmd);
2538 install_element(ENABLE_NODE, &copy_runningconf_startupconf_cmd);
2539 install_element(ENABLE_NODE, &config_write_cmd);
2540 install_element(ENABLE_NODE, &show_running_config_cmd);
d62a17ae 2541 install_element(ENABLE_NODE, &config_logmsg_cmd);
a83a5331 2542
d62a17ae 2543 install_default(CONFIG_NODE);
2544
5f6eaa9b 2545 event_cmd_init();
d62a17ae 2546 workqueue_cmd_init();
2547 hash_cmd_init();
2548 }
2549
2550 install_element(CONFIG_NODE, &hostname_cmd);
2551 install_element(CONFIG_NODE, &no_hostname_cmd);
6b3ee3a0
MK
2552 install_element(CONFIG_NODE, &domainname_cmd);
2553 install_element(CONFIG_NODE, &no_domainname_cmd);
d62a17ae 2554
2555 if (terminal > 0) {
0bdeb5e5
DL
2556 full_cli = true;
2557
85a6806d
MS
2558 install_element(CONFIG_NODE, &debug_memstats_cmd);
2559
d62a17ae 2560 install_element(CONFIG_NODE, &password_cmd);
322e2d5c 2561 install_element(CONFIG_NODE, &no_password_cmd);
d62a17ae 2562 install_element(CONFIG_NODE, &enable_password_cmd);
2563 install_element(CONFIG_NODE, &no_enable_password_cmd);
2564
d62a17ae 2565 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
2566 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
2567 install_element(CONFIG_NODE, &banner_motd_default_cmd);
2568 install_element(CONFIG_NODE, &banner_motd_file_cmd);
19d61463 2569 install_element(CONFIG_NODE, &banner_motd_line_cmd);
d62a17ae 2570 install_element(CONFIG_NODE, &no_banner_motd_cmd);
2571 install_element(CONFIG_NODE, &service_terminal_length_cmd);
2572 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
ac156aec
DA
2573 install_element(CONFIG_NODE, &allow_reserved_ranges_cmd);
2574 install_element(CONFIG_NODE, &no_allow_reserved_ranges_cmd);
d62a17ae 2575
0bdeb5e5 2576 log_cmd_init();
d62a17ae 2577 vrf_install_commands();
2578 }
af2567b6
DL
2579
2580#ifdef DEV_BUILD
d62a17ae 2581 grammar_sandbox_init();
af2567b6 2582#endif
718e3744 2583}
228da428 2584
4d762f26 2585void cmd_terminate(void)
d62a17ae 2586{
2587 struct cmd_node *cmd_node;
2588
5d806ec6
QY
2589 hook_unregister(cmd_execute, handle_pipe_action);
2590 hook_unregister(cmd_execute_done, handle_pipe_action_done);
2591
d62a17ae 2592 if (cmdvec) {
2593 for (unsigned int i = 0; i < vector_active(cmdvec); i++)
2594 if ((cmd_node = vector_slot(cmdvec, i)) != NULL) {
2595 // deleting the graph delets the cmd_element as
2596 // well
2597 graph_delete_graph(cmd_node->cmdgraph);
2598 vector_free(cmd_node->cmd_vector);
d8bc11a5 2599 hash_clean_and_free(&cmd_node->cmd_hash, NULL);
d62a17ae 2600 }
2601
2602 vector_free(cmdvec);
2603 cmdvec = NULL;
2604 }
2605
0a22ddfb 2606 XFREE(MTYPE_HOST, host.name);
46b48b33
DS
2607 XFREE(MTYPE_HOST, host.system);
2608 XFREE(MTYPE_HOST, host.release);
2609 XFREE(MTYPE_HOST, host.version);
0a22ddfb
QY
2610 XFREE(MTYPE_HOST, host.domainname);
2611 XFREE(MTYPE_HOST, host.password);
2612 XFREE(MTYPE_HOST, host.password_encrypt);
2613 XFREE(MTYPE_HOST, host.enable);
2614 XFREE(MTYPE_HOST, host.enable_encrypt);
0a22ddfb
QY
2615 XFREE(MTYPE_HOST, host.motdfile);
2616 XFREE(MTYPE_HOST, host.config);
19d61463 2617 XFREE(MTYPE_HOST, host.motd);
d62a17ae 2618
6a154c88 2619 list_delete(&varhandlers);
d62a17ae 2620 qobj_finish();
228da428 2621}