]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
Merge pull request #5410 from ton31337/feature/bgp_default-route_with_route-map_set
[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"
deaa50db 34#include "log_int.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"
d0bfb22c 50
eaf58ba9 51DEFINE_MTYPE_STATIC(LIB, HOST, "Host config")
d62a17ae 52DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
4a1ab8e4 53
26fbe472
QY
54#define item(x) \
55 { \
56 x, #x \
57 }
58
59/* clang-format off */
60const struct message tokennames[] = {
61 item(WORD_TKN),
62 item(VARIABLE_TKN),
63 item(RANGE_TKN),
64 item(IPV4_TKN),
65 item(IPV4_PREFIX_TKN),
66 item(IPV6_TKN),
67 item(IPV6_PREFIX_TKN),
68 item(MAC_TKN),
69 item(MAC_PREFIX_TKN),
70 item(FORK_TKN),
71 item(JOIN_TKN),
72 item(START_TKN),
73 item(END_TKN),
74 {0},
75};
76
154e9ca1 77const char *const node_names[] = {
a83a5331
QY
78 "auth", // AUTH_NODE,
79 "view", // VIEW_NODE,
80 "auth enable", // AUTH_ENABLE_NODE,
81 "enable", // ENABLE_NODE,
82 "config", // CONFIG_NODE,
a83a5331
QY
83 "debug", // DEBUG_NODE,
84 "vrf debug", // VRF_DEBUG_NODE,
1c2facd1 85 "northbound debug", // NORTHBOUND_DEBUG_NODE,
c652f6f6 86 "vnc debug", // DEBUG_VNC_NODE,
e3ab8170 87 "route-map debug", /* RMAP_DEBUG_NODE */
fe9e7b71 88 "resolver debug", /* RESOLVER_DEBUG_NODE */
a83a5331
QY
89 "aaa", // AAA_NODE,
90 "keychain", // KEYCHAIN_NODE,
9d356c93 91 "keychain key", // KEYCHAIN_KEY_NODE,
9f46cc36 92 "static ip", // IP_NODE,
a83a5331
QY
93 "vrf", // VRF_NODE,
94 "interface", // INTERFACE_NODE,
dba32923 95 "nexthop-group", // NH_GROUP_NODE,
a83a5331
QY
96 "zebra", // ZEBRA_NODE,
97 "table", // TABLE_NODE,
98 "rip", // RIP_NODE,
99 "ripng", // RIPNG_NODE,
100 "babel", // BABEL_NODE,
101 "eigrp", // EIGRP_NODE,
102 "bgp", // BGP_NODE,
103 "bgp vpnv4", // BGP_VPNV4_NODE,
c652f6f6 104 "bgp vpnv6", // BGP_VPNV6_NODE,
996c9314 105 "bgp ipv4 unicast", // BGP_IPV4_NODE,
a83a5331
QY
106 "bgp ipv4 multicast", // BGP_IPV4M_NODE,
107 "bgp ipv4 labeled unicast", // BGP_IPV4L_NODE,
108 "bgp ipv6", // BGP_IPV6_NODE,
109 "bgp ipv6 multicast", // BGP_IPV6M_NODE,
110 "bgp ipv6 labeled unicast", // BGP_IPV6L_NODE,
996c9314
LB
111 "bgp vrf policy", // BGP_VRF_POLICY_NODE,
112 "bgp vnc defaults", // BGP_VNC_DEFAULTS_NODE,
a83a5331
QY
113 "bgp vnc nve", // BGP_VNC_NVE_GROUP_NODE,
114 "bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
115 "rfp defaults", // RFP_DEFAULTS_NODE,
116 "bgp evpn", // BGP_EVPN_NODE,
117 "ospf", // OSPF_NODE,
118 "ospf6", // OSPF6_NODE,
119 "ldp", // LDP_NODE,
120 "ldp ipv4", // LDP_IPV4_NODE,
121 "ldp ipv6", // LDP_IPV6_NODE,
122 "ldp ipv4 interface", // LDP_IPV4_IFACE_NODE,
123 "ldp ipv6 interface", // LDP_IPV6_IFACE_NODE,
124 "ldp l2vpn", // LDP_L2VPN_NODE,
125 "ldp", // LDP_PSEUDOWIRE_NODE,
126 "isis", // ISIS_NODE,
996c9314
LB
127 "ipv4 access list", // ACCESS_NODE,
128 "ipv4 prefix list", // PREFIX_NODE,
129 "ipv6 access list", // ACCESS_IPV6_NODE,
130 "MAC access list", // ACCESS_MAC_NODE,
131 "ipv6 prefix list", // PREFIX_IPV6_NODE,
c652f6f6 132 "as list", // AS_LIST_NODE,
996c9314 133 "community list", // COMMUNITY_LIST_NODE,
a83a5331 134 "routemap", // RMAP_NODE,
e5c83d9b 135 "pbr-map", // PBRMAP_NODE,
a83a5331
QY
136 "smux", // SMUX_NODE,
137 "dump", // DUMP_NODE,
138 "forwarding", // FORWARDING_NODE,
139 "protocol", // PROTOCOL_NODE,
140 "mpls", // MPLS_NODE,
2dd0d726 141 "pw", // PW_NODE,
a83a5331
QY
142 "vty", // VTY_NODE,
143 "link-params", // LINK_PARAMS_NODE,
144 "bgp evpn vni", // BGP_EVPN_VNI_NODE,
dabecd7c 145 "rpki", // RPKI_NODE
7c40bf39 146 "bgp ipv4 flowspec", /* BGP_FLOWSPECV4_NODE
147 */
148 "bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE
149 */
c2f29cf3
RZ
150 "bfd", /* BFD_NODE */
151 "bfd peer", /* BFD_PEER_NODE */
7c0cbd0e 152 "openfabric", // OPENFABRIC_NODE
2fff50ec 153 "vrrp", /* VRRP_NODE */
ed18356f 154 "bmp", /* BMP_NODE */
a83a5331 155};
26fbe472 156/* clang-format on */
a83a5331 157
718e3744 158/* Command vector which includes some level of command lists. Normally
159 each daemon maintains each own cmdvec. */
eb820afe 160vector cmdvec = NULL;
718e3744 161
162/* Host information structure. */
163struct host host;
164
419cd5a0
MK
165/*
166 * Returns host.name if any, otherwise
167 * it returns the system hostname.
168 */
6b3ee3a0 169const char *cmd_hostname_get(void)
419cd5a0
MK
170{
171 return host.name;
172}
173
174/*
175 * Returns unix domainname
176 */
6b3ee3a0 177const char *cmd_domainname_get(void)
419cd5a0
MK
178{
179 return host.domainname;
180}
181
718e3744 182/* Standard command node structures. */
d62a17ae 183static struct cmd_node auth_node = {
9d303b37 184 AUTH_NODE, "Password: ",
718e3744 185};
186
d62a17ae 187static struct cmd_node view_node = {
9d303b37 188 VIEW_NODE, "%s> ",
718e3744 189};
190
d62a17ae 191static struct cmd_node auth_enable_node = {
9d303b37 192 AUTH_ENABLE_NODE, "Password: ",
718e3744 193};
194
d62a17ae 195static struct cmd_node enable_node = {
9d303b37 196 ENABLE_NODE, "%s# ",
718e3744 197};
198
d62a17ae 199static struct cmd_node config_node = {CONFIG_NODE, "%s(config)# ", 1};
6590f2c3 200
2d362d10 201static const struct facility_map {
d62a17ae 202 int facility;
203 const char *name;
204 size_t match;
205} syslog_facilities[] = {
206 {LOG_KERN, "kern", 1},
207 {LOG_USER, "user", 2},
208 {LOG_MAIL, "mail", 1},
209 {LOG_DAEMON, "daemon", 1},
210 {LOG_AUTH, "auth", 1},
211 {LOG_SYSLOG, "syslog", 1},
212 {LOG_LPR, "lpr", 2},
213 {LOG_NEWS, "news", 1},
214 {LOG_UUCP, "uucp", 2},
215 {LOG_CRON, "cron", 1},
274a4a44 216#ifdef LOG_FTP
d62a17ae 217 {LOG_FTP, "ftp", 1},
274a4a44 218#endif
d62a17ae 219 {LOG_LOCAL0, "local0", 6},
220 {LOG_LOCAL1, "local1", 6},
221 {LOG_LOCAL2, "local2", 6},
222 {LOG_LOCAL3, "local3", 6},
223 {LOG_LOCAL4, "local4", 6},
224 {LOG_LOCAL5, "local5", 6},
225 {LOG_LOCAL6, "local6", 6},
226 {LOG_LOCAL7, "local7", 6},
227 {0, NULL, 0},
228};
274a4a44 229
d62a17ae 230static const char *facility_name(int facility)
274a4a44 231{
d62a17ae 232 const struct facility_map *fm;
274a4a44 233
d62a17ae 234 for (fm = syslog_facilities; fm->name; fm++)
235 if (fm->facility == facility)
236 return fm->name;
237 return "";
274a4a44 238}
239
d62a17ae 240static int facility_match(const char *str)
274a4a44 241{
d62a17ae 242 const struct facility_map *fm;
274a4a44 243
d62a17ae 244 for (fm = syslog_facilities; fm->name; fm++)
245 if (!strncmp(str, fm->name, fm->match))
246 return fm->facility;
247 return -1;
274a4a44 248}
249
d62a17ae 250static int level_match(const char *s)
274a4a44 251{
d62a17ae 252 int level;
d0bfb22c 253
d62a17ae 254 for (level = 0; zlog_priority[level] != NULL; level++)
255 if (!strncmp(s, zlog_priority[level], 2))
256 return level;
257 return ZLOG_DISABLED;
274a4a44 258}
259
cb585b65 260/* This is called from main when a daemon is invoked with -v or --version. */
d62a17ae 261void print_version(const char *progname)
6590f2c3 262{
d62a17ae 263 printf("%s version %s\n", progname, FRR_VERSION);
264 printf("%s\n", FRR_COPYRIGHT);
265 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS);
6590f2c3 266}
267
d62a17ae 268char *argv_concat(struct cmd_token **argv, int argc, int shift)
269{
a6a87d63 270 int cnt = MAX(argc - shift, 0);
271 const char *argstr[cnt + 1];
272
273 if (!cnt)
274 return NULL;
fe011935
QY
275
276 for (int i = 0; i < cnt; i++)
277 argstr[i] = argv[i + shift]->arg;
278
279 return frrstr_join(argstr, cnt, " ");
280}
281
282vector cmd_make_strvec(const char *string)
283{
284 if (!string)
d62a17ae 285 return NULL;
fe011935
QY
286
287 const char *copy = string;
288
289 /* skip leading whitespace */
fefa5e0f 290 while (isspace((unsigned char)*copy) && *copy != '\0')
fe011935
QY
291 copy++;
292
293 /* if the entire string was whitespace or a comment, return */
294 if (*copy == '\0' || *copy == '!' || *copy == '#')
295 return NULL;
296
0a334343 297 vector result = frrstr_split_vec(copy, "\n\r\t ");
fe011935
QY
298
299 for (unsigned int i = 0; i < vector_active(result); i++) {
300 if (strlen(vector_slot(result, i)) == 0) {
301 XFREE(MTYPE_TMP, vector_slot(result, i));
f428cb8a 302 vector_unset(result, i);
fe011935 303 }
d62a17ae 304 }
f428cb8a
QY
305
306 vector_compact(result);
307
fe011935
QY
308 return result;
309}
310
311void cmd_free_strvec(vector v)
312{
313 frrstr_strvec_free(v);
718e3744 314}
315
ae19d7dd
QY
316/**
317 * Convenience function for accessing argv data.
318 *
319 * @param argc
320 * @param argv
321 * @param text definition snippet of the desired token
322 * @param index the starting index, and where to store the
323 * index of the found token if it exists
324 * @return 1 if found, 0 otherwise
325 */
d62a17ae 326int argv_find(struct cmd_token **argv, int argc, const char *text, int *index)
ae19d7dd 327{
d62a17ae 328 int found = 0;
329 for (int i = *index; i < argc && found == 0; i++)
330 if ((found = strmatch(text, argv[i]->text)))
331 *index = i;
332 return found;
ae19d7dd
QY
333}
334
d8b87afe 335static unsigned int cmd_hash_key(const void *p)
274f29b2 336{
bd74dc61
DS
337 int size = sizeof(p);
338
339 return jhash(p, size, 0);
274f29b2
PJ
340}
341
74df8d6d 342static bool cmd_hash_cmp(const void *a, const void *b)
274f29b2 343{
d62a17ae 344 return a == b;
274f29b2
PJ
345}
346
718e3744 347/* Install top node of command vector. */
d62a17ae 348void install_node(struct cmd_node *node, int (*func)(struct vty *))
718e3744 349{
d62a17ae 350 vector_set_index(cmdvec, node->node, node);
351 node->func = func;
352 node->cmdgraph = graph_new();
353 node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
354 // add start node
355 struct cmd_token *token =
356 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
357 graph_new_node(node->cmdgraph, token,
358 (void (*)(void *)) & cmd_token_del);
996c9314 359 node->cmd_hash = hash_create_size(16, cmd_hash_key, cmd_hash_cmp,
bd74dc61 360 "Command Hash");
718e3744 361}
362
718e3744 363/* Return prompt character of specified node. */
d62a17ae 364const char *cmd_prompt(enum node_type node)
718e3744 365{
d62a17ae 366 struct cmd_node *cnode;
718e3744 367
d62a17ae 368 cnode = vector_slot(cmdvec, node);
369 return cnode->prompt;
718e3744 370}
371
372/* Install a command into a node. */
154e9ca1 373void install_element(enum node_type ntype, const struct cmd_element *cmd)
718e3744 374{
d62a17ae 375 struct cmd_node *cnode;
d0bfb22c 376
d62a17ae 377 /* cmd_init hasn't been called */
378 if (!cmdvec) {
379 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
380 __func__);
381 return;
382 }
ebacb4ed 383
3cbb67f2 384 cnode = vector_lookup(cmdvec, ntype);
718e3744 385
d62a17ae 386 if (cnode == NULL) {
387 fprintf(stderr,
3cbb67f2
DL
388 "%s[%s]:\n"
389 "\tnode %d (%s) does not exist.\n"
390 "\tplease call install_node() before install_element()\n",
391 cmd->name, cmd->string, ntype, node_names[ntype]);
d62a17ae 392 exit(EXIT_FAILURE);
393 }
ebacb4ed 394
154e9ca1 395 if (hash_lookup(cnode->cmd_hash, (void *)cmd) != NULL) {
d62a17ae 396 fprintf(stderr,
3cbb67f2
DL
397 "%s[%s]:\n"
398 "\tnode %d (%s) already has this command installed.\n"
399 "\tduplicate install_element call?\n",
400 cmd->name, cmd->string, ntype, node_names[ntype]);
d62a17ae 401 return;
402 }
ebacb4ed 403
154e9ca1 404 assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern));
ebacb4ed 405
d62a17ae 406 struct graph *graph = graph_new();
407 struct cmd_token *token =
408 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
409 graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
de8f7a39 410
d62a17ae 411 cmd_graph_parse(graph, cmd);
412 cmd_graph_names(graph);
413 cmd_graph_merge(cnode->cmdgraph, graph, +1);
414 graph_delete_graph(graph);
de8f7a39 415
154e9ca1 416 vector_set(cnode->cmd_vector, (void *)cmd);
735e62a0 417
d62a17ae 418 if (ntype == VIEW_NODE)
419 install_element(ENABLE_NODE, cmd);
718e3744 420}
421
154e9ca1 422void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
de8f7a39 423{
d62a17ae 424 struct cmd_node *cnode;
de8f7a39 425
d62a17ae 426 /* cmd_init hasn't been called */
427 if (!cmdvec) {
428 fprintf(stderr, "%s called before cmd_init, breakage likely\n",
429 __func__);
430 return;
431 }
de8f7a39 432
3cbb67f2 433 cnode = vector_lookup(cmdvec, ntype);
de8f7a39 434
d62a17ae 435 if (cnode == NULL) {
436 fprintf(stderr,
3cbb67f2
DL
437 "%s[%s]:\n"
438 "\tnode %d (%s) does not exist.\n"
439 "\tplease call install_node() before uninstall_element()\n",
440 cmd->name, cmd->string, ntype, node_names[ntype]);
d62a17ae 441 exit(EXIT_FAILURE);
442 }
de8f7a39 443
154e9ca1 444 if (hash_release(cnode->cmd_hash, (void *)cmd) == NULL) {
d62a17ae 445 fprintf(stderr,
3cbb67f2
DL
446 "%s[%s]:\n"
447 "\tnode %d (%s) does not have this command installed.\n"
448 "\tduplicate uninstall_element call?\n",
449 cmd->name, cmd->string, ntype, node_names[ntype]);
d62a17ae 450 return;
451 }
de8f7a39 452
154e9ca1 453 vector_unset_value(cnode->cmd_vector, (void *)cmd);
de8f7a39 454
d62a17ae 455 struct graph *graph = graph_new();
456 struct cmd_token *token =
457 cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
458 graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
de8f7a39 459
d62a17ae 460 cmd_graph_parse(graph, cmd);
461 cmd_graph_names(graph);
462 cmd_graph_merge(cnode->cmdgraph, graph, -1);
463 graph_delete_graph(graph);
de8f7a39 464
d62a17ae 465 if (ntype == VIEW_NODE)
466 uninstall_element(ENABLE_NODE, cmd);
de8f7a39
DL
467}
468
469
2d362d10 470static const unsigned char itoa64[] =
d62a17ae 471 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
718e3744 472
d62a17ae 473static void to64(char *s, long v, int n)
718e3744 474{
d62a17ae 475 while (--n >= 0) {
476 *s++ = itoa64[v & 0x3f];
477 v >>= 6;
478 }
718e3744 479}
480
d62a17ae 481static char *zencrypt(const char *passwd)
718e3744 482{
d62a17ae 483 char salt[6];
484 struct timeval tv;
485 char *crypt(const char *, const char *);
718e3744 486
d62a17ae 487 gettimeofday(&tv, 0);
d0bfb22c 488
d62a17ae 489 to64(&salt[0], random(), 3);
490 to64(&salt[3], tv.tv_usec, 3);
491 salt[5] = '\0';
718e3744 492
d62a17ae 493 return crypt(passwd, salt);
718e3744 494}
495
496/* This function write configuration of this host. */
d62a17ae 497static int config_write_host(struct vty *vty)
498{
6b3ee3a0
MK
499 if (cmd_hostname_get())
500 vty_out(vty, "hostname %s\n", cmd_hostname_get());
d62a17ae 501
3b103fec
MK
502 if (cmd_domainname_get())
503 vty_out(vty, "domainname %s\n", cmd_domainname_get());
504
0204baa8 505 /* The following are all configuration commands that are not sent to
3518f352
DS
506 * watchfrr. For instance watchfrr is hardcoded to log to syslog so
507 * we would always display 'log syslog informational' in the config
508 * which would cause other daemons to then switch to syslog when they
509 * parse frr.conf.
510 */
0204baa8
DW
511 if (strcmp(zlog_default->protoname, "WATCHFRR")) {
512 if (host.encrypt) {
513 if (host.password_encrypt)
3518f352
DS
514 vty_out(vty, "password 8 %s\n",
515 host.password_encrypt);
0204baa8
DW
516 if (host.enable_encrypt)
517 vty_out(vty, "enable password 8 %s\n",
518 host.enable_encrypt);
519 } else {
520 if (host.password)
521 vty_out(vty, "password %s\n", host.password);
522 if (host.enable)
3518f352
DS
523 vty_out(vty, "enable password %s\n",
524 host.enable);
0204baa8 525 }
d62a17ae 526
0204baa8 527 if (host.logfile
3518f352
DS
528 && (zlog_default->maxlvl[ZLOG_DEST_FILE]
529 != ZLOG_DISABLED)) {
0204baa8
DW
530 vty_out(vty, "log file %s", host.logfile);
531 if (zlog_default->maxlvl[ZLOG_DEST_FILE]
532 != zlog_default->default_lvl)
533 vty_out(vty, " %s",
534 zlog_priority
3518f352
DS
535 [zlog_default->maxlvl
536 [ZLOG_DEST_FILE]]);
0204baa8
DW
537 vty_out(vty, "\n");
538 }
d62a17ae 539
0204baa8
DW
540 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) {
541 vty_out(vty, "log stdout");
542 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT]
543 != zlog_default->default_lvl)
544 vty_out(vty, " %s",
3518f352
DS
545 zlog_priority
546 [zlog_default->maxlvl
547 [ZLOG_DEST_STDOUT]]);
0204baa8
DW
548 vty_out(vty, "\n");
549 }
d62a17ae 550
0204baa8
DW
551 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
552 vty_out(vty, "no log monitor\n");
553 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR]
554 != zlog_default->default_lvl)
555 vty_out(vty, "log monitor %s\n",
d62a17ae 556 zlog_priority[zlog_default->maxlvl
3518f352 557 [ZLOG_DEST_MONITOR]]);
0204baa8
DW
558
559 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) {
560 vty_out(vty, "log syslog");
561 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG]
562 != zlog_default->default_lvl)
563 vty_out(vty, " %s",
564 zlog_priority[zlog_default->maxlvl
565 [ZLOG_DEST_SYSLOG]]);
566 vty_out(vty, "\n");
567 }
d62a17ae 568
0204baa8
DW
569 if (zlog_default->facility != LOG_DAEMON)
570 vty_out(vty, "log facility %s\n",
571 facility_name(zlog_default->facility));
d62a17ae 572
0204baa8
DW
573 if (zlog_default->record_priority == 1)
574 vty_out(vty, "log record-priority\n");
d62a17ae 575
0204baa8
DW
576 if (zlog_default->timestamp_precision > 0)
577 vty_out(vty, "log timestamp precision %d\n",
578 zlog_default->timestamp_precision);
d62a17ae 579
0204baa8
DW
580 if (host.advanced)
581 vty_out(vty, "service advanced-vty\n");
d62a17ae 582
0204baa8
DW
583 if (host.encrypt)
584 vty_out(vty, "service password-encryption\n");
d62a17ae 585
0204baa8 586 if (host.lines >= 0)
3518f352
DS
587 vty_out(vty, "service terminal-length %d\n",
588 host.lines);
d62a17ae 589
0204baa8
DW
590 if (host.motdfile)
591 vty_out(vty, "banner motd file %s\n", host.motdfile);
19d61463
DA
592 else if (host.motd
593 && strncmp(host.motd, FRR_DEFAULT_MOTD,
594 strlen(host.motd)))
595 vty_out(vty, "banner motd line %s\n", host.motd);
0204baa8
DW
596 else if (!host.motd)
597 vty_out(vty, "no banner motd\n");
598 }
d62a17ae 599
9eed278b
DL
600 if (debug_memstats_at_exit)
601 vty_out(vty, "!\ndebug memstats-at-exit\n");
602
d62a17ae 603 return 1;
718e3744 604}
605
d0bfb22c 606/* Utility function for getting command graph. */
d62a17ae 607static struct graph *cmd_node_graph(vector v, enum node_type ntype)
718e3744 608{
d62a17ae 609 struct cmd_node *cnode = vector_slot(v, ntype);
610 return cnode->cmdgraph;
718e3744 611}
612
d62a17ae 613static int cmd_try_do_shortcut(enum node_type node, char *first_word)
614{
615 if (first_word != NULL && node != AUTH_NODE && node != VIEW_NODE
616 && node != AUTH_ENABLE_NODE && 0 == strcmp("do", first_word))
617 return 1;
618 return 0;
718e3744 619}
620
d0bfb22c
QY
621/**
622 * Compare function for cmd_token.
623 * Used with qsort to sort command completions.
624 */
d62a17ae 625static int compare_completions(const void *fst, const void *snd)
718e3744 626{
36de6e0e
A
627 const struct cmd_token *first = *(const struct cmd_token * const *)fst,
628 *secnd = *(const struct cmd_token * const *)snd;
d62a17ae 629 return strcmp(first->text, secnd->text);
718e3744 630}
631
d0bfb22c
QY
632/**
633 * Takes a list of completions returned by command_complete,
634 * dedeuplicates them based on both text and description,
6011c1b2
QY
635 * sorts them, and returns them as a vector.
636 *
637 * @param completions linked list of cmd_token
638 * @return deduplicated and sorted vector with
d0bfb22c 639 */
d62a17ae 640vector completions_to_vec(struct list *completions)
641{
642 vector comps = vector_init(VECTOR_MIN_SIZE);
643
644 struct listnode *ln;
645 struct cmd_token *token, *cr = NULL;
646 unsigned int i, exists;
647 for (ALL_LIST_ELEMENTS_RO(completions, ln, token)) {
648 if (token->type == END_TKN && (cr = token))
649 continue;
650
651 // linear search for token in completions vector
652 exists = 0;
653 for (i = 0; i < vector_active(comps) && !exists; i++) {
654 struct cmd_token *curr = vector_slot(comps, i);
53205694 655#ifdef VTYSH_DEBUG
d62a17ae 656 exists = !strcmp(curr->text, token->text)
657 && !strcmp(curr->desc, token->desc);
53205694 658#else
d62a17ae 659 exists = !strcmp(curr->text, token->text);
53205694 660#endif /* VTYSH_DEBUG */
d62a17ae 661 }
909a2155 662
d62a17ae 663 if (!exists)
664 vector_set(comps, token);
665 }
cd40b329 666
d62a17ae 667 // sort completions
668 qsort(comps->index, vector_active(comps), sizeof(void *),
669 &compare_completions);
cd40b329 670
d62a17ae 671 // make <cr> the first element, if it is present
672 if (cr) {
673 vector_set_index(comps, vector_active(comps), NULL);
674 memmove(comps->index + 1, comps->index,
675 (comps->alloced - 1) * sizeof(void *));
676 vector_set_index(comps, 0, cr);
677 }
6011c1b2 678
d62a17ae 679 return comps;
cd40b329 680}
d0bfb22c
QY
681/**
682 * Generates a vector of cmd_token representing possible completions
683 * on the current input.
684 *
685 * @param vline the vectorized input line
686 * @param vty the vty with the node to match on
687 * @param status pointer to matcher status code
ebacb4ed 688 * @return vector of struct cmd_token * with possible completions
d0bfb22c 689 */
d62a17ae 690static vector cmd_complete_command_real(vector vline, struct vty *vty,
691 int *status)
cd40b329 692{
d62a17ae 693 struct list *completions;
694 struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
cd40b329 695
d62a17ae 696 enum matcher_rv rv = command_complete(cmdgraph, vline, &completions);
cd40b329 697
d62a17ae 698 if (MATCHER_ERROR(rv)) {
699 *status = CMD_ERR_NO_MATCH;
700 return NULL;
701 }
b92938a7 702
d62a17ae 703 vector comps = completions_to_vec(completions);
6a154c88 704 list_delete(&completions);
b92938a7 705
d62a17ae 706 // set status code appropriately
707 switch (vector_active(comps)) {
708 case 0:
709 *status = CMD_ERR_NO_MATCH;
710 break;
711 case 1:
712 *status = CMD_COMPLETE_FULL_MATCH;
713 break;
714 default:
715 *status = CMD_COMPLETE_LIST_MATCH;
716 }
718e3744 717
d62a17ae 718 return comps;
d0bfb22c 719}
718e3744 720
d62a17ae 721vector cmd_describe_command(vector vline, struct vty *vty, int *status)
d0bfb22c 722{
d62a17ae 723 vector ret;
718e3744 724
d62a17ae 725 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
726 enum node_type onode;
1c2facd1 727 int orig_xpath_index;
d62a17ae 728 vector shifted_vline;
729 unsigned int index;
718e3744 730
d62a17ae 731 onode = vty->node;
1c2facd1 732 orig_xpath_index = vty->xpath_index;
d62a17ae 733 vty->node = ENABLE_NODE;
1c2facd1 734 vty->xpath_index = 0;
d62a17ae 735 /* We can try it on enable node, cos' the vty is authenticated
736 */
718e3744 737
d62a17ae 738 shifted_vline = vector_init(vector_count(vline));
739 /* use memcpy? */
740 for (index = 1; index < vector_active(vline); index++) {
741 vector_set_index(shifted_vline, index - 1,
742 vector_lookup(vline, index));
743 }
718e3744 744
d62a17ae 745 ret = cmd_complete_command_real(shifted_vline, vty, status);
d0bfb22c 746
d62a17ae 747 vector_free(shifted_vline);
748 vty->node = onode;
1c2facd1 749 vty->xpath_index = orig_xpath_index;
d62a17ae 750 return ret;
751 }
718e3744 752
d62a17ae 753 return cmd_complete_command_real(vline, vty, status);
718e3744 754}
755
70d44c5c
DL
756static struct list *varhandlers = NULL;
757
d62a17ae 758void cmd_variable_complete(struct cmd_token *token, const char *arg,
759 vector comps)
760{
761 struct listnode *ln;
762 const struct cmd_variable_handler *cvh;
763 size_t i, argsz;
764 vector tmpcomps;
765
766 tmpcomps = arg ? vector_init(VECTOR_MIN_SIZE) : comps;
767
768 for (ALL_LIST_ELEMENTS_RO(varhandlers, ln, cvh)) {
769 if (cvh->tokenname && strcmp(cvh->tokenname, token->text))
770 continue;
9d303b37
DL
771 if (cvh->varname && (!token->varname
772 || strcmp(cvh->varname, token->varname)))
d62a17ae 773 continue;
774 cvh->completions(tmpcomps, token);
775 break;
776 }
777
778 if (!arg)
779 return;
780
781 argsz = strlen(arg);
782 for (i = vector_active(tmpcomps); i; i--) {
783 char *item = vector_slot(tmpcomps, i - 1);
784 if (strlen(item) >= argsz && !strncmp(item, arg, argsz))
785 vector_set(comps, item);
786 else
787 XFREE(MTYPE_COMPLETION, item);
788 }
789 vector_free(tmpcomps);
70d44c5c
DL
790}
791
1a0f614d
QY
792#define AUTOCOMP_INDENT 5
793
d62a17ae 794char *cmd_variable_comp2str(vector comps, unsigned short cols)
1a0f614d 795{
d62a17ae 796 size_t bsz = 16;
797 char *buf = XCALLOC(MTYPE_TMP, bsz);
798 int lc = AUTOCOMP_INDENT;
799 size_t cs = AUTOCOMP_INDENT;
800 size_t itemlen;
801 snprintf(buf, bsz, "%*s", AUTOCOMP_INDENT, "");
802 for (size_t j = 0; j < vector_active(comps); j++) {
803 char *item = vector_slot(comps, j);
804 itemlen = strlen(item);
1a0f614d 805
d62a17ae 806 if (cs + itemlen + AUTOCOMP_INDENT + 3 >= bsz)
807 buf = XREALLOC(MTYPE_TMP, buf, (bsz *= 2));
1a0f614d 808
d62a17ae 809 if (lc + itemlen + 1 >= cols) {
810 cs += snprintf(&buf[cs], bsz - cs, "\n%*s",
811 AUTOCOMP_INDENT, "");
812 lc = AUTOCOMP_INDENT;
813 }
1a0f614d 814
d62a17ae 815 size_t written = snprintf(&buf[cs], bsz - cs, "%s ", item);
816 lc += written;
817 cs += written;
818 XFREE(MTYPE_COMPLETION, item);
819 vector_set_index(comps, j, NULL);
820 }
821 return buf;
1a0f614d
QY
822}
823
d62a17ae 824void cmd_variable_handler_register(const struct cmd_variable_handler *cvh)
70d44c5c 825{
d62a17ae 826 if (!varhandlers)
827 return;
70d44c5c 828
d62a17ae 829 for (; cvh->completions; cvh++)
830 listnode_add(varhandlers, (void *)cvh);
70d44c5c
DL
831}
832
7f059ea6
DL
833DEFUN_HIDDEN (autocomplete,
834 autocomplete_cmd,
835 "autocomplete TYPE TEXT VARNAME",
836 "Autocompletion handler (internal, for vtysh)\n"
837 "cmd_token->type\n"
838 "cmd_token->text\n"
839 "cmd_token->varname\n")
840{
d62a17ae 841 struct cmd_token tok;
842 vector comps = vector_init(32);
843 size_t i;
7f059ea6 844
d62a17ae 845 memset(&tok, 0, sizeof(tok));
846 tok.type = atoi(argv[1]->arg);
847 tok.text = argv[2]->arg;
848 tok.varname = argv[3]->arg;
849 if (!strcmp(tok.varname, "-"))
850 tok.varname = NULL;
7f059ea6 851
d62a17ae 852 cmd_variable_complete(&tok, NULL, comps);
7f059ea6 853
d62a17ae 854 for (i = 0; i < vector_active(comps); i++) {
855 char *text = vector_slot(comps, i);
856 vty_out(vty, "%s\n", text);
857 XFREE(MTYPE_COMPLETION, text);
858 }
7f059ea6 859
d62a17ae 860 vector_free(comps);
861 return CMD_SUCCESS;
7f059ea6
DL
862}
863
ebacb4ed
QY
864/**
865 * Generate possible tab-completions for the given input. This function only
866 * returns results that would result in a valid command if used as Readline
867 * completions (as is the case in vtysh). For instance, if the passed vline ends
868 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
869 *
870 * @param vline vectorized input line
871 * @param vty the vty
872 * @param status location to store matcher status code in
873 * @return set of valid strings for use with Readline as tab-completions.
874 */
875
d62a17ae 876char **cmd_complete_command(vector vline, struct vty *vty, int *status)
877{
878 char **ret = NULL;
879 int original_node = vty->node;
880 vector input_line = vector_init(vector_count(vline));
881
882 // if the first token is 'do' we'll want to execute the command in the
883 // enable node
884 int do_shortcut = cmd_try_do_shortcut(vty->node, vector_slot(vline, 0));
885 vty->node = do_shortcut ? ENABLE_NODE : original_node;
886
887 // construct the input line we'll be matching on
888 unsigned int offset = (do_shortcut) ? 1 : 0;
889 for (unsigned index = 0; index + offset < vector_active(vline); index++)
890 vector_set_index(input_line, index,
891 vector_lookup(vline, index + offset));
892
893 // get token completions -- this is a copying operation
894 vector comps = NULL, initial_comps;
895 initial_comps = cmd_complete_command_real(input_line, vty, status);
896
897 if (!MATCHER_ERROR(*status)) {
898 assert(initial_comps);
899 // filter out everything that is not suitable for a
900 // tab-completion
901 comps = vector_init(VECTOR_MIN_SIZE);
902 for (unsigned int i = 0; i < vector_active(initial_comps);
903 i++) {
904 struct cmd_token *token = vector_slot(initial_comps, i);
905 if (token->type == WORD_TKN)
906 vector_set(comps, XSTRDUP(MTYPE_COMPLETION,
907 token->text));
908 else if (IS_VARYING_TOKEN(token->type)) {
909 const char *ref = vector_lookup(
910 vline, vector_active(vline) - 1);
911 cmd_variable_complete(token, ref, comps);
912 }
913 }
914 vector_free(initial_comps);
915
916 // since we filtered results, we need to re-set status code
917 switch (vector_active(comps)) {
918 case 0:
919 *status = CMD_ERR_NO_MATCH;
920 break;
921 case 1:
922 *status = CMD_COMPLETE_FULL_MATCH;
923 break;
924 default:
925 *status = CMD_COMPLETE_LIST_MATCH;
926 }
927
928 // copy completions text into an array of char*
929 ret = XMALLOC(MTYPE_TMP,
930 (vector_active(comps) + 1) * sizeof(char *));
931 unsigned int i;
932 for (i = 0; i < vector_active(comps); i++) {
933 ret[i] = vector_slot(comps, i);
934 }
935 // set the last element to NULL, because this array is used in
936 // a Readline completion_generator function which expects NULL
937 // as a sentinel value
938 ret[i] = NULL;
939 vector_free(comps);
940 comps = NULL;
941 } else if (initial_comps)
942 vector_free(initial_comps);
943
944 // comps should always be null here
945 assert(!comps);
946
947 // free the adjusted input line
948 vector_free(input_line);
949
950 // reset vty->node to its original value
951 vty->node = original_node;
952
953 return ret;
cde9f101 954}
b92938a7 955
b92938a7 956/* return parent node */
957/* MUST eventually converge on CONFIG_NODE */
d62a17ae 958enum node_type node_parent(enum node_type node)
959{
960 enum node_type ret;
961
962 assert(node > CONFIG_NODE);
963
964 switch (node) {
965 case BGP_VPNV4_NODE:
966 case BGP_VPNV6_NODE:
7c40bf39 967 case BGP_FLOWSPECV4_NODE:
968 case BGP_FLOWSPECV6_NODE:
d62a17ae 969 case BGP_VRF_POLICY_NODE:
970 case BGP_VNC_DEFAULTS_NODE:
971 case BGP_VNC_NVE_GROUP_NODE:
972 case BGP_VNC_L2_GROUP_NODE:
973 case BGP_IPV4_NODE:
974 case BGP_IPV4M_NODE:
975 case BGP_IPV4L_NODE:
976 case BGP_IPV6_NODE:
977 case BGP_IPV6M_NODE:
978 case BGP_EVPN_NODE:
979 case BGP_IPV6L_NODE:
ed18356f 980 case BMP_NODE:
d62a17ae 981 ret = BGP_NODE;
982 break;
983 case BGP_EVPN_VNI_NODE:
984 ret = BGP_EVPN_NODE;
985 break;
986 case KEYCHAIN_KEY_NODE:
987 ret = KEYCHAIN_NODE;
988 break;
989 case LINK_PARAMS_NODE:
990 ret = INTERFACE_NODE;
991 break;
992 case LDP_IPV4_NODE:
993 case LDP_IPV6_NODE:
994 ret = LDP_NODE;
995 break;
996 case LDP_IPV4_IFACE_NODE:
997 ret = LDP_IPV4_NODE;
998 break;
999 case LDP_IPV6_IFACE_NODE:
1000 ret = LDP_IPV6_NODE;
1001 break;
1002 case LDP_PSEUDOWIRE_NODE:
1003 ret = LDP_L2VPN_NODE;
1004 break;
c2f29cf3
RZ
1005 case BFD_PEER_NODE:
1006 ret = BFD_NODE;
1007 break;
d62a17ae 1008 default:
1009 ret = CONFIG_NODE;
1010 break;
1011 }
1012
1013 return ret;
b92938a7 1014}
1015
718e3744 1016/* Execute command by argument vline vector. */
c139972c 1017static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
d62a17ae 1018 struct vty *vty,
1019 const struct cmd_element **cmd)
1020{
1021 struct list *argv_list;
1022 enum matcher_rv status;
1023 const struct cmd_element *matched_element = NULL;
1024
1025 struct graph *cmdgraph = cmd_node_graph(cmdvec, vty->node);
1026 status = command_match(cmdgraph, vline, &argv_list, &matched_element);
1027
1028 if (cmd)
1029 *cmd = matched_element;
1030
1031 // if matcher error, return corresponding CMD_ERR
1032 if (MATCHER_ERROR(status)) {
1033 if (argv_list)
6a154c88 1034 list_delete(&argv_list);
d62a17ae 1035 switch (status) {
1036 case MATCHER_INCOMPLETE:
1037 return CMD_ERR_INCOMPLETE;
1038 case MATCHER_AMBIGUOUS:
1039 return CMD_ERR_AMBIGUOUS;
1040 default:
1041 return CMD_ERR_NO_MATCH;
1042 }
1043 }
1044
1045 // build argv array from argv list
1046 struct cmd_token **argv = XMALLOC(
1047 MTYPE_TMP, argv_list->count * sizeof(struct cmd_token *));
1048 struct listnode *ln;
1049 struct cmd_token *token;
1050 unsigned int i = 0;
1051 for (ALL_LIST_ELEMENTS_RO(argv_list, ln, token))
1052 argv[i++] = token;
1053
1054 int argc = argv_list->count;
1055
1056 int ret;
1057 if (matched_element->daemon)
1058 ret = CMD_SUCCESS_DAEMON;
a6233bfc 1059 else {
eaf6705d
RW
1060 if (vty->config) {
1061 /* Clear array of enqueued configuration changes. */
1062 vty->num_cfg_changes = 0;
1063 memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
1064
689b9cf5
RW
1065 /* Regenerate candidate configuration if necessary. */
1066 if (frr_get_cli_mode() == FRR_CLI_CLASSIC
1067 && running_config->version
1068 > vty->candidate_config->version)
eaf6705d
RW
1069 nb_config_replace(vty->candidate_config,
1070 running_config, true);
1071 }
a6233bfc 1072
d62a17ae 1073 ret = matched_element->func(matched_element, vty, argc, argv);
a6233bfc 1074 }
d62a17ae 1075
1076 // delete list and cmd_token's in it
6a154c88 1077 list_delete(&argv_list);
d62a17ae 1078 XFREE(MTYPE_TMP, argv);
1079
1080 return ret;
718e3744 1081}
1082
cd40b329
CF
1083/**
1084 * Execute a given command, handling things like "do ..." and checking
1085 * whether the given command might apply at a parent node if doesn't
1086 * apply for the current node.
1087 *
1088 * @param vline Command line input, vector of char* where each element is
1089 * one input token.
1090 * @param vty The vty context in which the command should be executed.
1091 * @param cmd Pointer where the struct cmd_element of the matched command
1092 * will be stored, if any. May be set to NULL if this info is
1093 * not needed.
1094 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1095 * @return The status of the command that has been executed or an error code
1096 * as to why no command could be executed.
1097 */
d62a17ae 1098int cmd_execute_command(vector vline, struct vty *vty,
1099 const struct cmd_element **cmd, int vtysh)
17aca20b 1100{
d62a17ae 1101 int ret, saved_ret = 0;
1102 enum node_type onode, try_node;
1c2facd1 1103 int orig_xpath_index;
eda031f6 1104
d62a17ae 1105 onode = try_node = vty->node;
1c2facd1 1106 orig_xpath_index = vty->xpath_index;
b92938a7 1107
d62a17ae 1108 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1109 vector shifted_vline;
1110 unsigned int index;
b92938a7 1111
d62a17ae 1112 vty->node = ENABLE_NODE;
1c2facd1 1113 vty->xpath_index = 0;
d62a17ae 1114 /* We can try it on enable node, cos' the vty is authenticated
1115 */
b92938a7 1116
d62a17ae 1117 shifted_vline = vector_init(vector_count(vline));
1118 /* use memcpy? */
1119 for (index = 1; index < vector_active(vline); index++)
1120 vector_set_index(shifted_vline, index - 1,
1121 vector_lookup(vline, index));
b92938a7 1122
d62a17ae 1123 ret = cmd_execute_command_real(shifted_vline, FILTER_RELAXED,
1124 vty, cmd);
b92938a7 1125
d62a17ae 1126 vector_free(shifted_vline);
1127 vty->node = onode;
1c2facd1 1128 vty->xpath_index = orig_xpath_index;
d62a17ae 1129 return ret;
1130 }
b92938a7 1131
d62a17ae 1132 saved_ret = ret =
1133 cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd);
b92938a7 1134
d62a17ae 1135 if (vtysh)
1136 return saved_ret;
87d683b0 1137
825d5fbf 1138 if (ret != CMD_SUCCESS && ret != CMD_WARNING
d741915e 1139 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
825d5fbf 1140 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
d62a17ae 1141 /* This assumes all nodes above CONFIG_NODE are childs of
1142 * CONFIG_NODE */
1143 while (vty->node > CONFIG_NODE) {
1144 try_node = node_parent(try_node);
1145 vty->node = try_node;
1c2facd1
RW
1146 if (vty->xpath_index > 0)
1147 vty->xpath_index--;
d62a17ae 1148 ret = cmd_execute_command_real(vline, FILTER_RELAXED,
1149 vty, cmd);
825d5fbf 1150 if (ret == CMD_SUCCESS || ret == CMD_WARNING
d741915e 1151 || ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE
825d5fbf
CS
1152 || ret == CMD_NOT_MY_INSTANCE
1153 || ret == CMD_WARNING_CONFIG_FAILED)
d62a17ae 1154 return ret;
1155 }
1156 /* no command succeeded, reset the vty to the original node */
1157 vty->node = onode;
1c2facd1 1158 vty->xpath_index = orig_xpath_index;
d62a17ae 1159 }
04e64062 1160
d62a17ae 1161 /* return command status for original node */
1162 return saved_ret;
b92938a7 1163}
1164
cd40b329
CF
1165/**
1166 * Execute a given command, matching it strictly against the current node.
1167 * This mode is used when reading config files.
1168 *
1169 * @param vline Command line input, vector of char* where each element is
1170 * one input token.
1171 * @param vty The vty context in which the command should be executed.
1172 * @param cmd Pointer where the struct cmd_element* of the matched command
1173 * will be stored, if any. May be set to NULL if this info is
1174 * not needed.
1175 * @return The status of the command that has been executed or an error code
1176 * as to why no command could be executed.
1177 */
d62a17ae 1178int cmd_execute_command_strict(vector vline, struct vty *vty,
1179 const struct cmd_element **cmd)
718e3744 1180{
d62a17ae 1181 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
718e3744 1182}
1183
01e24c4a
QY
1184/*
1185 * Hook for preprocessing command string before executing.
1186 *
1187 * All subscribers are called with the raw command string that is to be
1188 * executed. If any changes are to be made, a new string should be allocated
1189 * with MTYPE_TMP and *cmd_out updated to point to this new string. The caller
1190 * is then responsible for freeing this string.
1191 *
1192 * All processing functions must be mutually exclusive in their action, i.e. if
1193 * one subscriber decides to modify the command, all others must not modify it
1194 * when called. Feeding the output of one processing command into a subsequent
1195 * one is not supported.
1196 *
1197 * This hook is intentionally internal to the command processing system.
1198 *
1199 * cmd_in
1200 * The raw command string.
1201 *
1202 * cmd_out
1203 * The result of any processing.
1204 */
1205DECLARE_HOOK(cmd_execute,
0a334343 1206 (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a 1207 (vty, cmd_in, cmd_out));
0a334343 1208DEFINE_HOOK(cmd_execute, (struct vty *vty, const char *cmd_in, char **cmd_out),
01e24c4a
QY
1209 (vty, cmd_in, cmd_out));
1210
1211/* Hook executed after a CLI command. */
0a334343 1212DECLARE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a 1213 (vty, cmd_exec));
0a334343 1214DEFINE_KOOH(cmd_execute_done, (struct vty *vty, const char *cmd_exec),
01e24c4a
QY
1215 (vty, cmd_exec));
1216
fe6b47b9
QY
1217/*
1218 * cmd_execute hook subscriber to handle `|` actions.
1219 */
1220static int handle_pipe_action(struct vty *vty, const char *cmd_in,
1221 char **cmd_out)
1222{
1223 /* look for `|` */
9f227e4c 1224 char *orig, *working, *token, *u;
fe6b47b9
QY
1225 char *pipe = strstr(cmd_in, "| ");
1226
1227 if (!pipe)
1228 return 0;
1229
1230 /* duplicate string for processing purposes, not including pipe */
1231 orig = working = XSTRDUP(MTYPE_TMP, pipe + 2);
1232
1233 /* retrieve action */
1234 token = strsep(&working, " ");
4f4060f6 1235 assert(token);
fe6b47b9
QY
1236
1237 /* match result to known actions */
1238 if (strmatch(token, "include")) {
1239 /* the remaining text should be a regexp */
1240 char *regexp = working;
5d806ec6
QY
1241
1242 if (!regexp) {
1243 vty_out(vty, "%% Need a regexp to filter with\n");
1244 goto fail;
1245 }
1246
fe6b47b9 1247 bool succ = vty_set_include(vty, regexp);
0a334343 1248
fe6b47b9 1249 if (!succ) {
5d806ec6 1250 vty_out(vty, "%% Bad regexp '%s'\n", regexp);
fe6b47b9
QY
1251 goto fail;
1252 }
2cddf2ff 1253 *cmd_out = XSTRDUP(MTYPE_TMP, cmd_in);
9f227e4c 1254 u = *cmd_out;
1255 strsep(&u, "|");
fe6b47b9 1256 } else {
5d806ec6 1257 vty_out(vty, "%% Unknown action '%s'\n", token);
fe6b47b9
QY
1258 goto fail;
1259 }
1260
1261fail:
1262 XFREE(MTYPE_TMP, orig);
1263 return 0;
1264}
1265
1266static int handle_pipe_action_done(struct vty *vty, const char *cmd_exec)
1267{
0b42d81a 1268 if (vty->filter)
fe6b47b9 1269 vty_set_include(vty, NULL);
0b42d81a 1270
fe6b47b9
QY
1271 return 0;
1272}
1273
01e24c4a
QY
1274int cmd_execute(struct vty *vty, const char *cmd,
1275 const struct cmd_element **matched, int vtysh)
1276{
1277 int ret;
1278 char *cmd_out = NULL;
1279 const char *cmd_exec;
1280 vector vline;
1281
1282 hook_call(cmd_execute, vty, cmd, &cmd_out);
1283 cmd_exec = cmd_out ? (const char *)cmd_out : cmd;
1284
1285 vline = cmd_make_strvec(cmd_exec);
1286
1287 if (vline) {
1288 ret = cmd_execute_command(vline, vty, matched, vtysh);
1289 cmd_free_strvec(vline);
1290 } else {
1291 ret = CMD_SUCCESS;
1292 }
1293
1294 hook_call(cmd_execute_done, vty, cmd_exec);
1295
0a22ddfb 1296 XFREE(MTYPE_TMP, cmd_out);
01e24c4a
QY
1297
1298 return ret;
1299}
1300
1301
bed578b8 1302/**
d62a17ae 1303 * Parse one line of config, walking up the parse tree attempting to find a
1304 * match
bed578b8
DS
1305 *
1306 * @param vty The vty context in which the command should be executed.
1307 * @param cmd Pointer where the struct cmd_element* of the match command
1308 * will be stored, if any. May be set to NULL if this info is
1309 * not needed.
d62a17ae 1310 * @param use_daemon Boolean to control whether or not we match on
1311 * CMD_SUCCESS_DAEMON
bed578b8
DS
1312 * or not.
1313 * @return The status of the command that has been executed or an error code
1314 * as to why no command could be executed.
1315 */
d62a17ae 1316int command_config_read_one_line(struct vty *vty,
7ab57d19
DS
1317 const struct cmd_element **cmd,
1318 uint32_t line_num, int use_daemon)
bed578b8 1319{
d62a17ae 1320 vector vline;
d62a17ae 1321 int ret;
bed578b8 1322
d62a17ae 1323 vline = cmd_make_strvec(vty->buf);
bed578b8 1324
d62a17ae 1325 /* In case of comment line */
1326 if (vline == NULL)
1327 return CMD_SUCCESS;
bed578b8 1328
d62a17ae 1329 /* Execute configuration command : this is strict match */
1330 ret = cmd_execute_command_strict(vline, vty, cmd);
bed578b8 1331
d62a17ae 1332 // Climb the tree and try the command again at each node
1333 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1334 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1335 && ret != CMD_SUCCESS && ret != CMD_WARNING
d741915e 1336 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
996c9314 1337 && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
d62a17ae 1338 && vty->node != CONFIG_NODE) {
1c2facd1
RW
1339 int saved_node = vty->node;
1340 int saved_xpath_index = vty->xpath_index;
bed578b8 1341
d62a17ae 1342 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1343 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1344 && ret != CMD_SUCCESS && ret != CMD_WARNING
d741915e 1345 && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
d62a17ae 1346 && vty->node > CONFIG_NODE) {
1347 vty->node = node_parent(vty->node);
1c2facd1
RW
1348 if (vty->xpath_index > 0)
1349 vty->xpath_index--;
d62a17ae 1350 ret = cmd_execute_command_strict(vline, vty, cmd);
1351 }
bed578b8 1352
d62a17ae 1353 // If climbing the tree did not work then ignore the command and
1354 // stay at the same node
1355 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
1356 && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
1357 && ret != CMD_SUCCESS && ret != CMD_WARNING) {
1358 vty->node = saved_node;
1c2facd1 1359 vty->xpath_index = saved_xpath_index;
d62a17ae 1360 }
1361 }
bed578b8 1362
b45d8ccc
DS
1363 if (ret != CMD_SUCCESS &&
1364 ret != CMD_WARNING &&
1365 ret != CMD_SUCCESS_DAEMON) {
7ab57d19
DS
1366 struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve));
1367
1368 memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ);
1369 ve->line_num = line_num;
1370 if (!vty->error)
1371 vty->error = list_new();
1372
1373 listnode_add(vty->error, ve);
1374 }
cbd7259d 1375
d62a17ae 1376 cmd_free_strvec(vline);
bed578b8 1377
d62a17ae 1378 return ret;
bed578b8
DS
1379}
1380
5689fe5f 1381/* Configuration make from file. */
d62a17ae 1382int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num)
718e3744 1383{
d62a17ae 1384 int ret, error_ret = 0;
1385 *line_num = 0;
718e3744 1386
d62a17ae 1387 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
7ab57d19 1388 ++(*line_num);
13fbc82d 1389
7ab57d19 1390 ret = command_config_read_one_line(vty, NULL, *line_num, 0);
718e3744 1391
d62a17ae 1392 if (ret != CMD_SUCCESS && ret != CMD_WARNING
1393 && ret != CMD_ERR_NOTHING_TODO)
1394 error_ret = ret;
1395 }
5689fe5f 1396
d62a17ae 1397 if (error_ret) {
1398 return error_ret;
1399 }
5689fe5f 1400
d62a17ae 1401 return CMD_SUCCESS;
718e3744 1402}
1403
5689fe5f 1404/* Configuration from terminal */
718e3744 1405DEFUN (config_terminal,
1406 config_terminal_cmd,
dc1c13c0 1407 "configure [terminal]",
718e3744 1408 "Configuration from vty interface\n"
1409 "Configuration terminal\n")
1410{
f344c66e 1411 return vty_config_enter(vty, false, false);
718e3744 1412}
1413
1414/* Enable command */
d0bfb22c 1415DEFUN (enable,
718e3744 1416 config_enable_cmd,
1417 "enable",
1418 "Turn on privileged mode command\n")
1419{
d62a17ae 1420 /* If enable password is NULL, change to ENABLE_NODE */
1421 if ((host.enable == NULL && host.enable_encrypt == NULL)
1422 || vty->type == VTY_SHELL_SERV)
1423 vty->node = ENABLE_NODE;
1424 else
1425 vty->node = AUTH_ENABLE_NODE;
718e3744 1426
d62a17ae 1427 return CMD_SUCCESS;
718e3744 1428}
1429
1430/* Disable command */
d0bfb22c 1431DEFUN (disable,
718e3744 1432 config_disable_cmd,
1433 "disable",
1434 "Turn off privileged mode command\n")
1435{
d62a17ae 1436 if (vty->node == ENABLE_NODE)
1437 vty->node = VIEW_NODE;
1438 return CMD_SUCCESS;
718e3744 1439}
1440
1441/* Down vty node level. */
1442DEFUN (config_exit,
1443 config_exit_cmd,
1444 "exit",
1445 "Exit current mode and down to previous mode\n")
0b84f294 1446{
d62a17ae 1447 cmd_exit(vty);
1448 return CMD_SUCCESS;
1449}
1450
1451void cmd_exit(struct vty *vty)
1452{
1453 switch (vty->node) {
1454 case VIEW_NODE:
1455 case ENABLE_NODE:
1456 if (vty_shell(vty))
1457 exit(0);
1458 else
1459 vty->status = VTY_CLOSE;
1460 break;
1461 case CONFIG_NODE:
1462 vty->node = ENABLE_NODE;
f344c66e 1463 vty_config_exit(vty);
d62a17ae 1464 break;
1465 case INTERFACE_NODE:
2dd0d726 1466 case PW_NODE:
d62a17ae 1467 case VRF_NODE:
dba32923 1468 case NH_GROUP_NODE:
d62a17ae 1469 case ZEBRA_NODE:
1470 case BGP_NODE:
1471 case RIP_NODE:
1472 case EIGRP_NODE:
1473 case BABEL_NODE:
1474 case RIPNG_NODE:
1475 case OSPF_NODE:
1476 case OSPF6_NODE:
1477 case LDP_NODE:
1478 case LDP_L2VPN_NODE:
1479 case ISIS_NODE:
7c0cbd0e 1480 case OPENFABRIC_NODE:
d62a17ae 1481 case KEYCHAIN_NODE:
d62a17ae 1482 case RMAP_NODE:
e5c83d9b 1483 case PBRMAP_NODE:
d62a17ae 1484 case VTY_NODE:
c2f29cf3 1485 case BFD_NODE:
d62a17ae 1486 vty->node = CONFIG_NODE;
1487 break;
1488 case BGP_IPV4_NODE:
1489 case BGP_IPV4M_NODE:
1490 case BGP_IPV4L_NODE:
1491 case BGP_VPNV4_NODE:
1492 case BGP_VPNV6_NODE:
7c40bf39 1493 case BGP_FLOWSPECV4_NODE:
1494 case BGP_FLOWSPECV6_NODE:
d62a17ae 1495 case BGP_VRF_POLICY_NODE:
1496 case BGP_VNC_DEFAULTS_NODE:
1497 case BGP_VNC_NVE_GROUP_NODE:
1498 case BGP_VNC_L2_GROUP_NODE:
1499 case BGP_IPV6_NODE:
1500 case BGP_IPV6M_NODE:
1501 case BGP_EVPN_NODE:
1502 case BGP_IPV6L_NODE:
ed18356f 1503 case BMP_NODE:
d62a17ae 1504 vty->node = BGP_NODE;
1505 break;
1506 case BGP_EVPN_VNI_NODE:
1507 vty->node = BGP_EVPN_NODE;
1508 break;
1509 case LDP_IPV4_NODE:
1510 case LDP_IPV6_NODE:
1511 vty->node = LDP_NODE;
1512 break;
1513 case LDP_IPV4_IFACE_NODE:
1514 vty->node = LDP_IPV4_NODE;
1515 break;
1516 case LDP_IPV6_IFACE_NODE:
1517 vty->node = LDP_IPV6_NODE;
1518 break;
1519 case LDP_PSEUDOWIRE_NODE:
1520 vty->node = LDP_L2VPN_NODE;
1521 break;
1522 case KEYCHAIN_KEY_NODE:
1523 vty->node = KEYCHAIN_NODE;
1524 break;
1525 case LINK_PARAMS_NODE:
1526 vty->node = INTERFACE_NODE;
1527 break;
c2f29cf3
RZ
1528 case BFD_PEER_NODE:
1529 vty->node = BFD_NODE;
1530 break;
d62a17ae 1531 default:
1532 break;
1533 }
1c2facd1
RW
1534
1535 if (vty->xpath_index > 0)
1536 vty->xpath_index--;
718e3744 1537}
1538
f667a580
QY
1539/* ALIAS_FIXME */
1540DEFUN (config_quit,
1541 config_quit_cmd,
1542 "quit",
1543 "Exit current mode and down to previous mode\n")
1544{
d62a17ae 1545 return config_exit(self, vty, argc, argv);
f667a580
QY
1546}
1547
d0bfb22c 1548
718e3744 1549/* End of configuration. */
1550DEFUN (config_end,
1551 config_end_cmd,
1552 "end",
efd7904e 1553 "End current mode and change to enable mode.\n")
718e3744 1554{
cf09d3ca 1555 if (vty->config) {
f344c66e 1556 vty_config_exit(vty);
d62a17ae 1557 vty->node = ENABLE_NODE;
d62a17ae 1558 }
1c2facd1 1559
d62a17ae 1560 return CMD_SUCCESS;
718e3744 1561}
1562
1563/* Show version. */
1564DEFUN (show_version,
1565 show_version_cmd,
1566 "show version",
1567 SHOW_STR
1568 "Displays zebra version\n")
1569{
d62a17ae 1570 vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION,
6b3ee3a0 1571 cmd_hostname_get() ? cmd_hostname_get() : "");
d62a17ae 1572 vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO);
1573 vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS);
718e3744 1574
d62a17ae 1575 return CMD_SUCCESS;
718e3744 1576}
1577
1578/* Help display function for all node. */
1579DEFUN (config_help,
1580 config_help_cmd,
1581 "help",
1582 "Description of the interactive help system\n")
1583{
d62a17ae 1584 vty_out(vty,
1585 "Quagga VTY provides advanced help feature. When you need help,\n\
61b7d449
DL
1586anytime at the command line please press '?'.\n\
1587\n\
1588If nothing matches, the help list will be empty and you must backup\n\
1589 until entering a '?' shows the available options.\n\
1590Two styles of help are provided:\n\
15911. Full help is available when you are ready to enter a\n\
1592command argument (e.g. 'show ?') and describes each possible\n\
1593argument.\n\
15942. Partial help is provided when an abbreviated argument is entered\n\
1595 and you want to know what arguments match the input\n\
1596 (e.g. 'show me?'.)\n\n");
d62a17ae 1597 return CMD_SUCCESS;
1598}
1599
1600static void permute(struct graph_node *start, struct vty *vty)
1601{
1602 static struct list *position = NULL;
1603 if (!position)
1604 position = list_new();
1605
1606 struct cmd_token *stok = start->data;
1607 struct graph_node *gnn;
1608 struct listnode *ln;
1609
1610 // recursive dfs
1611 listnode_add(position, start);
1612 for (unsigned int i = 0; i < vector_active(start->to); i++) {
1613 struct graph_node *gn = vector_slot(start->to, i);
1614 struct cmd_token *tok = gn->data;
1615 if (tok->attr == CMD_ATTR_HIDDEN
1616 || tok->attr == CMD_ATTR_DEPRECATED)
1617 continue;
1618 else if (tok->type == END_TKN || gn == start) {
1619 vty_out(vty, " ");
1620 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
1621 struct cmd_token *tt = gnn->data;
1622 if (tt->type < SPECIAL_TKN)
1623 vty_out(vty, " %s", tt->text);
1624 }
1625 if (gn == start)
1626 vty_out(vty, "...");
1627 vty_out(vty, "\n");
1628 } else {
1629 bool skip = false;
1630 if (stok->type == FORK_TKN && tok->type != FORK_TKN)
1631 for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
1632 if (gnn == gn) {
1633 skip = true;
1634 break;
1635 }
1636 if (!skip)
1637 permute(gn, vty);
1638 }
1639 }
1640 list_delete_node(position, listtail(position));
1641}
1642
1643int cmd_list_cmds(struct vty *vty, int do_permute)
1644{
1645 struct cmd_node *node = vector_slot(cmdvec, vty->node);
1646
1647 if (do_permute)
1648 permute(vector_slot(node->cmdgraph->nodes, 0), vty);
1649 else {
1650 /* loop over all commands at this node */
154e9ca1 1651 const struct cmd_element *element = NULL;
d62a17ae 1652 for (unsigned int i = 0; i < vector_active(node->cmd_vector);
1653 i++)
1654 if ((element = vector_slot(node->cmd_vector, i))
1655 && element->attr != CMD_ATTR_DEPRECATED
1656 && element->attr != CMD_ATTR_HIDDEN)
1657 vty_out(vty, " %s\n", element->string);
1658 }
1659 return CMD_SUCCESS;
718e3744 1660}
1661
0b84f294
DL
1662/* Help display function for all node. */
1663DEFUN (config_list,
1664 config_list_cmd,
1665 "list [permutations]",
1666 "Print command list\n"
1667 "Print all possible command permutations\n")
1668{
d62a17ae 1669 return cmd_list_cmds(vty, argc == 2);
0b84f294
DL
1670}
1671
a2454870
QY
1672DEFUN (show_commandtree,
1673 show_commandtree_cmd,
1674 "show commandtree [permutations]",
1675 SHOW_STR
5a1945e4
DS
1676 "Show command tree\n"
1677 "Permutations that we are interested in\n")
a2454870 1678{
d62a17ae 1679 return cmd_list_cmds(vty, argc == 3);
a2454870
QY
1680}
1681
26fbe472
QY
1682DEFUN_HIDDEN(show_cli_graph,
1683 show_cli_graph_cmd,
1684 "show cli graph",
1685 SHOW_STR
1686 "CLI reflection\n"
1687 "Dump current command space as DOT graph\n")
1688{
1689 struct cmd_node *cn = vector_slot(cmdvec, vty->node);
1690 char *dot = cmd_graph_dump_dot(cn->cmdgraph);
1691
1692 vty_out(vty, "%s\n", dot);
1693 XFREE(MTYPE_TMP, dot);
1694 return CMD_SUCCESS;
1695}
1696
f806f29c 1697static int vty_write_config(struct vty *vty)
8efe88ea 1698{
d62a17ae 1699 size_t i;
1700 struct cmd_node *node;
8efe88ea 1701
f806f29c 1702 if (host.noconfig)
1703 return CMD_SUCCESS;
1704
5e6a9350
RW
1705 nb_cli_show_config_prepare(running_config, false);
1706
d62a17ae 1707 if (vty->type == VTY_TERM) {
1708 vty_out(vty, "\nCurrent configuration:\n");
1709 vty_out(vty, "!\n");
1710 }
8efe88ea 1711
ac4adef4
DL
1712 if (strcmp(frr_defaults_version(), FRR_VER_SHORT))
1713 vty_out(vty, "! loaded from %s\n", frr_defaults_version());
d62a17ae 1714 vty_out(vty, "frr version %s\n", FRR_VER_SHORT);
ac4adef4 1715 vty_out(vty, "frr defaults %s\n", frr_defaults_profile());
d62a17ae 1716 vty_out(vty, "!\n");
8efe88ea 1717
8685be73
RW
1718 for (i = 0; i < vector_active(cmdvec); i++)
1719 if ((node = vector_slot(cmdvec, i)) && node->func
1720 && (node->vtysh || vty->type != VTY_SHELL)) {
1721 if ((*node->func)(vty))
1722 vty_out(vty, "!\n");
1723 }
8efe88ea 1724
d62a17ae 1725 if (vty->type == VTY_TERM) {
1726 vty_out(vty, "end\n");
1727 }
8efe88ea 1728
f806f29c 1729 return CMD_SUCCESS;
1730}
d862bffb 1731
f806f29c 1732static int file_write_config(struct vty *vty)
718e3744 1733{
d62a17ae 1734 int fd, dirfd;
1735 char *config_file, *slash;
1736 char *config_file_tmp = NULL;
1737 char *config_file_sav = NULL;
1738 int ret = CMD_WARNING;
1739 struct vty *file_vty;
1740 struct stat conf_stat;
1741
d62a17ae 1742 if (host.noconfig)
1743 return CMD_SUCCESS;
1744
1745 /* Check and see if we are operating under vtysh configuration */
1746 if (host.config == NULL) {
1747 vty_out(vty,
1748 "Can't save to configuration file, using vtysh.\n");
1749 return CMD_WARNING;
1750 }
1751
1752 /* Get filename. */
1753 config_file = host.config;
d0bfb22c 1754
056cfe49
DL
1755#ifndef O_DIRECTORY
1756#define O_DIRECTORY 0
1757#endif
d62a17ae 1758 slash = strrchr(config_file, '/');
1759 if (slash) {
1760 char *config_dir = XSTRDUP(MTYPE_TMP, config_file);
1761 config_dir[slash - config_file] = '\0';
1762 dirfd = open(config_dir, O_DIRECTORY | O_RDONLY);
1763 XFREE(MTYPE_TMP, config_dir);
1764 } else
1765 dirfd = open(".", O_DIRECTORY | O_RDONLY);
1766 /* if dirfd is invalid, directory sync fails, but we're still OK */
1767
9f73d2c9
QY
1768 size_t config_file_sav_sz = strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1;
1769 config_file_sav = XMALLOC(MTYPE_TMP, config_file_sav_sz);
1770 strlcpy(config_file_sav, config_file, config_file_sav_sz);
1771 strlcat(config_file_sav, CONF_BACKUP_EXT, config_file_sav_sz);
d62a17ae 1772
1773
1774 config_file_tmp = XMALLOC(MTYPE_TMP, strlen(config_file) + 8);
1775 sprintf(config_file_tmp, "%s.XXXXXX", config_file);
1776
1777 /* Open file to configuration write. */
1778 fd = mkstemp(config_file_tmp);
1779 if (fd < 0) {
1780 vty_out(vty, "Can't open configuration file %s.\n",
1781 config_file_tmp);
1782 goto finished;
1783 }
1784 if (fchmod(fd, CONFIGFILE_MASK) != 0) {
1785 vty_out(vty, "Can't chmod configuration file %s: %s (%d).\n",
1786 config_file_tmp, safe_strerror(errno), errno);
1787 goto finished;
1788 }
1789
1790 /* Make vty for configuration file. */
1791 file_vty = vty_new();
1792 file_vty->wfd = fd;
1793 file_vty->type = VTY_FILE;
1794
1795 /* Config file header print. */
1796 vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! ");
1797 vty_time_print(file_vty, 1);
1798 vty_out(file_vty, "!\n");
1799 vty_write_config(file_vty);
1800 vty_close(file_vty);
1801
1802 if (stat(config_file, &conf_stat) >= 0) {
1803 if (unlink(config_file_sav) != 0)
1804 if (errno != ENOENT) {
1805 vty_out(vty,
1806 "Can't unlink backup configuration file %s.\n",
1807 config_file_sav);
1808 goto finished;
1809 }
1810 if (link(config_file, config_file_sav) != 0) {
1811 vty_out(vty,
1812 "Can't backup old configuration file %s.\n",
1813 config_file_sav);
1814 goto finished;
1815 }
1816 if (dirfd >= 0)
1817 fsync(dirfd);
1818 }
1819 if (rename(config_file_tmp, config_file) != 0) {
1820 vty_out(vty, "Can't save configuration file %s.\n",
1821 config_file);
1822 goto finished;
1823 }
1824 if (dirfd >= 0)
1825 fsync(dirfd);
1826
1827 vty_out(vty, "Configuration saved to %s\n", config_file);
1828 ret = CMD_SUCCESS;
05865c90 1829
1830finished:
d62a17ae 1831 if (ret != CMD_SUCCESS)
1832 unlink(config_file_tmp);
1833 if (dirfd >= 0)
1834 close(dirfd);
1835 XFREE(MTYPE_TMP, config_file_tmp);
1836 XFREE(MTYPE_TMP, config_file_sav);
1837 return ret;
718e3744 1838}
1839
f806f29c 1840/* Write current configuration into file. */
1841
1842DEFUN (config_write,
1843 config_write_cmd,
1844 "write [<file|memory|terminal>]",
1845 "Write running configuration to memory, network, or terminal\n"
1846 "Write to configuration file\n"
1847 "Write configuration currently in memory\n"
1848 "Write configuration to terminal\n")
1849{
1850 const int idx_type = 1;
1851
1852 // if command was 'write terminal' or 'write memory'
1853 if (argc == 2 && (!strcmp(argv[idx_type]->text, "terminal"))) {
1854 return vty_write_config(vty);
1855 }
1856
1857 return file_write_config(vty);
1858}
1859
d862bffb
QY
1860/* ALIAS_FIXME for 'write <terminal|memory>' */
1861DEFUN (show_running_config,
1862 show_running_config_cmd,
1863 "show running-config",
1864 SHOW_STR
f806f29c 1865 "running configuration (same as write terminal)\n")
d862bffb 1866{
f806f29c 1867 return vty_write_config(vty);
d862bffb 1868}
718e3744 1869
d862bffb
QY
1870/* ALIAS_FIXME for 'write file' */
1871DEFUN (copy_runningconf_startupconf,
1872 copy_runningconf_startupconf_cmd,
1873 "copy running-config startup-config",
1874 "Copy configuration\n"
1875 "Copy running config to... \n"
f806f29c 1876 "Copy running config to startup config (same as write file/memory)\n")
d862bffb 1877{
f806f29c 1878 return file_write_config(vty);
d862bffb
QY
1879}
1880/** -- **/
718e3744 1881
1882/* Write startup configuration into the terminal. */
1883DEFUN (show_startup_config,
1884 show_startup_config_cmd,
1885 "show startup-config",
1886 SHOW_STR
d0bfb22c 1887 "Contents of startup configuration\n")
718e3744 1888{
d62a17ae 1889 char buf[BUFSIZ];
1890 FILE *confp;
718e3744 1891
d62a17ae 1892 if (host.noconfig)
1893 return CMD_SUCCESS;
1894 if (host.config == NULL)
1895 return CMD_WARNING;
87f44e2f 1896
d62a17ae 1897 confp = fopen(host.config, "r");
1898 if (confp == NULL) {
1899 vty_out(vty, "Can't open configuration file [%s] due to '%s'\n",
1900 host.config, safe_strerror(errno));
1901 return CMD_WARNING;
1902 }
718e3744 1903
d62a17ae 1904 while (fgets(buf, BUFSIZ, confp)) {
1905 char *cp = buf;
718e3744 1906
d62a17ae 1907 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
1908 cp++;
1909 *cp = '\0';
718e3744 1910
d62a17ae 1911 vty_out(vty, "%s\n", buf);
1912 }
718e3744 1913
d62a17ae 1914 fclose(confp);
718e3744 1915
d62a17ae 1916 return CMD_SUCCESS;
718e3744 1917}
1918
6b3ee3a0
MK
1919int cmd_domainname_set(const char *domainname)
1920{
1921 XFREE(MTYPE_HOST, host.domainname);
1922 host.domainname = domainname ? XSTRDUP(MTYPE_HOST, domainname) : NULL;
1923 return CMD_SUCCESS;
1924}
1925
1926/* Hostname configuration */
60466a63
QY
1927DEFUN(config_domainname,
1928 domainname_cmd,
1929 "domainname WORD",
1930 "Set system's domain name\n"
1931 "This system's domain name\n")
6b3ee3a0
MK
1932{
1933 struct cmd_token *word = argv[1];
1934
fefa5e0f 1935 if (!isalpha((unsigned char)word->arg[0])) {
6b3ee3a0
MK
1936 vty_out(vty, "Please specify string starting with alphabet\n");
1937 return CMD_WARNING_CONFIG_FAILED;
1938 }
1939
1940 return cmd_domainname_set(word->arg);
1941}
1942
60466a63
QY
1943DEFUN(config_no_domainname,
1944 no_domainname_cmd,
1945 "no domainname [DOMAINNAME]",
1946 NO_STR
1947 "Reset system's domain name\n"
1948 "domain name of this router\n")
6b3ee3a0
MK
1949{
1950 return cmd_domainname_set(NULL);
1951}
1952
d62a17ae 1953int cmd_hostname_set(const char *hostname)
bff9c3e9 1954{
d62a17ae 1955 XFREE(MTYPE_HOST, host.name);
1956 host.name = hostname ? XSTRDUP(MTYPE_HOST, hostname) : NULL;
1957 return CMD_SUCCESS;
bff9c3e9
DL
1958}
1959
718e3744 1960/* Hostname configuration */
d0bfb22c 1961DEFUN (config_hostname,
718e3744 1962 hostname_cmd,
1963 "hostname WORD",
1964 "Set system's network name\n"
1965 "This system's network name\n")
1966{
d62a17ae 1967 struct cmd_token *word = argv[1];
d0bfb22c 1968
fefa5e0f 1969 if (!isalnum((unsigned char)word->arg[0])) {
63e653a2
LK
1970 vty_out(vty,
1971 "Please specify string starting with alphabet or number\n");
1972 return CMD_WARNING_CONFIG_FAILED;
1973 }
1974
1975 /* With reference to RFC 1123 Section 2.1 */
1976 if (strlen(word->arg) > HOSTNAME_LEN) {
1977 vty_out(vty, "Hostname length should be less than %d chars\n",
1978 HOSTNAME_LEN);
d62a17ae 1979 return CMD_WARNING_CONFIG_FAILED;
1980 }
718e3744 1981
d62a17ae 1982 return cmd_hostname_set(word->arg);
718e3744 1983}
1984
d0bfb22c 1985DEFUN (config_no_hostname,
718e3744 1986 no_hostname_cmd,
1987 "no hostname [HOSTNAME]",
1988 NO_STR
1989 "Reset system's network name\n"
1990 "Host name of this router\n")
1991{
d62a17ae 1992 return cmd_hostname_set(NULL);
718e3744 1993}
1994
1995/* VTY interface password set. */
f412b39a
DW
1996DEFUN (config_password,
1997 password_cmd,
98463e0a 1998 "password [(8-8)] WORD",
322e2d5c 1999 "Modify the terminal connection password\n"
718e3744 2000 "Specifies a HIDDEN password will follow\n"
d0bfb22c 2001 "The password string\n")
718e3744 2002{
d62a17ae 2003 int idx_8 = 1;
2004 int idx_word = 2;
2005 if (argc == 3) // '8' was specified
2006 {
2007 if (host.password)
2008 XFREE(MTYPE_HOST, host.password);
2009 host.password = NULL;
2010 if (host.password_encrypt)
2011 XFREE(MTYPE_HOST, host.password_encrypt);
2012 host.password_encrypt =
2013 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
2014 return CMD_SUCCESS;
2015 }
2016
fefa5e0f 2017 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 2018 vty_out(vty,
2019 "Please specify string starting with alphanumeric\n");
2020 return CMD_WARNING_CONFIG_FAILED;
2021 }
2022
2023 if (host.password)
2024 XFREE(MTYPE_HOST, host.password);
2025 host.password = NULL;
2026
2027 if (host.encrypt) {
2028 if (host.password_encrypt)
2029 XFREE(MTYPE_HOST, host.password_encrypt);
2030 host.password_encrypt =
2031 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
2032 } else
2033 host.password = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
2034
2035 return CMD_SUCCESS;
718e3744 2036}
2037
322e2d5c
PM
2038/* VTY interface password delete. */
2039DEFUN (no_config_password,
2040 no_password_cmd,
2041 "no password",
2042 NO_STR
2043 "Modify the terminal connection password\n")
2044{
2045 bool warned = false;
2046
2047 if (host.password) {
eb83f7ce 2048 if (!vty_shell_serv(vty)) {
4911ca9c 2049 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
2050 warned = true;
2051 }
322e2d5c
PM
2052 XFREE(MTYPE_HOST, host.password);
2053 }
2054 host.password = NULL;
2055
2056 if (host.password_encrypt) {
eb83f7ce 2057 if (!warned && !vty_shell_serv(vty))
4911ca9c 2058 vty_out(vty, NO_PASSWD_CMD_WARNING);
322e2d5c
PM
2059 XFREE(MTYPE_HOST, host.password_encrypt);
2060 }
2061 host.password_encrypt = NULL;
2062
2063 return CMD_SUCCESS;
2064}
2065
718e3744 2066/* VTY enable password set. */
f412b39a
DW
2067DEFUN (config_enable_password,
2068 enable_password_cmd,
98463e0a 2069 "enable password [(8-8)] WORD",
718e3744 2070 "Modify enable password parameters\n"
2071 "Assign the privileged level password\n"
2072 "Specifies a HIDDEN password will follow\n"
718e3744 2073 "The HIDDEN 'enable' password string\n")
2074{
d62a17ae 2075 int idx_8 = 2;
2076 int idx_word = 3;
2077
2078 /* Crypt type is specified. */
2079 if (argc == 4) {
2080 if (argv[idx_8]->arg[0] == '8') {
2081 if (host.enable)
2082 XFREE(MTYPE_HOST, host.enable);
2083 host.enable = NULL;
2084
2085 if (host.enable_encrypt)
2086 XFREE(MTYPE_HOST, host.enable_encrypt);
2087 host.enable_encrypt =
2088 XSTRDUP(MTYPE_HOST, argv[idx_word]->arg);
2089
2090 return CMD_SUCCESS;
2091 } else {
2092 vty_out(vty, "Unknown encryption type.\n");
2093 return CMD_WARNING_CONFIG_FAILED;
2094 }
2095 }
2096
fefa5e0f 2097 if (!isalnum((unsigned char)argv[idx_8]->arg[0])) {
d62a17ae 2098 vty_out(vty,
2099 "Please specify string starting with alphanumeric\n");
2100 return CMD_WARNING_CONFIG_FAILED;
2101 }
2102
2103 if (host.enable)
2104 XFREE(MTYPE_HOST, host.enable);
2105 host.enable = NULL;
2106
2107 /* Plain password input. */
2108 if (host.encrypt) {
2109 if (host.enable_encrypt)
2110 XFREE(MTYPE_HOST, host.enable_encrypt);
2111 host.enable_encrypt =
2112 XSTRDUP(MTYPE_HOST, zencrypt(argv[idx_8]->arg));
2113 } else
2114 host.enable = XSTRDUP(MTYPE_HOST, argv[idx_8]->arg);
2115
2116 return CMD_SUCCESS;
718e3744 2117}
2118
718e3744 2119/* VTY enable password delete. */
f412b39a
DW
2120DEFUN (no_config_enable_password,
2121 no_enable_password_cmd,
718e3744 2122 "no enable password",
2123 NO_STR
2124 "Modify enable password parameters\n"
2125 "Assign the privileged level password\n")
2126{
322e2d5c
PM
2127 bool warned = false;
2128
2129 if (host.enable) {
eb83f7ce 2130 if (!vty_shell_serv(vty)) {
4911ca9c 2131 vty_out(vty, NO_PASSWD_CMD_WARNING);
eb83f7ce
PM
2132 warned = true;
2133 }
d62a17ae 2134 XFREE(MTYPE_HOST, host.enable);
322e2d5c 2135 }
d62a17ae 2136 host.enable = NULL;
718e3744 2137
322e2d5c 2138 if (host.enable_encrypt) {
eb83f7ce 2139 if (!warned && !vty_shell_serv(vty))
4911ca9c 2140 vty_out(vty, NO_PASSWD_CMD_WARNING);
d62a17ae 2141 XFREE(MTYPE_HOST, host.enable_encrypt);
322e2d5c 2142 }
d62a17ae 2143 host.enable_encrypt = NULL;
718e3744 2144
d62a17ae 2145 return CMD_SUCCESS;
718e3744 2146}
d0bfb22c 2147
718e3744 2148DEFUN (service_password_encrypt,
2149 service_password_encrypt_cmd,
2150 "service password-encryption",
2151 "Set up miscellaneous service\n"
2152 "Enable encrypted passwords\n")
2153{
d62a17ae 2154 if (host.encrypt)
2155 return CMD_SUCCESS;
718e3744 2156
d62a17ae 2157 host.encrypt = 1;
718e3744 2158
d62a17ae 2159 if (host.password) {
2160 if (host.password_encrypt)
2161 XFREE(MTYPE_HOST, host.password_encrypt);
2162 host.password_encrypt =
2163 XSTRDUP(MTYPE_HOST, zencrypt(host.password));
2164 }
2165 if (host.enable) {
2166 if (host.enable_encrypt)
2167 XFREE(MTYPE_HOST, host.enable_encrypt);
2168 host.enable_encrypt =
2169 XSTRDUP(MTYPE_HOST, zencrypt(host.enable));
2170 }
718e3744 2171
d62a17ae 2172 return CMD_SUCCESS;
718e3744 2173}
2174
2175DEFUN (no_service_password_encrypt,
2176 no_service_password_encrypt_cmd,
2177 "no service password-encryption",
2178 NO_STR
2179 "Set up miscellaneous service\n"
2180 "Enable encrypted passwords\n")
2181{
d62a17ae 2182 if (!host.encrypt)
2183 return CMD_SUCCESS;
718e3744 2184
d62a17ae 2185 host.encrypt = 0;
718e3744 2186
d62a17ae 2187 if (host.password_encrypt)
2188 XFREE(MTYPE_HOST, host.password_encrypt);
2189 host.password_encrypt = NULL;
718e3744 2190
d62a17ae 2191 if (host.enable_encrypt)
2192 XFREE(MTYPE_HOST, host.enable_encrypt);
2193 host.enable_encrypt = NULL;
718e3744 2194
d62a17ae 2195 return CMD_SUCCESS;
718e3744 2196}
2197
f412b39a
DW
2198DEFUN (config_terminal_length,
2199 config_terminal_length_cmd,
d0bfb22c 2200 "terminal length (0-512)",
718e3744 2201 "Set terminal line parameters\n"
2202 "Set number of lines on a screen\n"
2203 "Number of lines on screen (0 for no pausing)\n")
2204{
d62a17ae 2205 int idx_number = 2;
718e3744 2206
d62a17ae 2207 vty->lines = atoi(argv[idx_number]->arg);
718e3744 2208
d62a17ae 2209 return CMD_SUCCESS;
718e3744 2210}
2211
f412b39a
DW
2212DEFUN (config_terminal_no_length,
2213 config_terminal_no_length_cmd,
718e3744 2214 "terminal no length",
2215 "Set terminal line parameters\n"
2216 NO_STR
2217 "Set number of lines on a screen\n")
2218{
d62a17ae 2219 vty->lines = -1;
2220 return CMD_SUCCESS;
718e3744 2221}
2222
f412b39a
DW
2223DEFUN (service_terminal_length,
2224 service_terminal_length_cmd,
d0bfb22c 2225 "service terminal-length (0-512)",
718e3744 2226 "Set up miscellaneous service\n"
2227 "System wide terminal length configuration\n"
2228 "Number of lines of VTY (0 means no line control)\n")
2229{
d62a17ae 2230 int idx_number = 2;
718e3744 2231
d62a17ae 2232 host.lines = atoi(argv[idx_number]->arg);
718e3744 2233
d62a17ae 2234 return CMD_SUCCESS;
718e3744 2235}
2236
f412b39a
DW
2237DEFUN (no_service_terminal_length,
2238 no_service_terminal_length_cmd,
d0bfb22c 2239 "no service terminal-length [(0-512)]",
718e3744 2240 NO_STR
2241 "Set up miscellaneous service\n"
2242 "System wide terminal length configuration\n"
2243 "Number of lines of VTY (0 means no line control)\n")
2244{
d62a17ae 2245 host.lines = -1;
2246 return CMD_SUCCESS;
718e3744 2247}
2248
2885f72d 2249DEFUN_HIDDEN (do_echo,
d0bfb22c
QY
2250 echo_cmd,
2251 "echo MESSAGE...",
2252 "Echo a message back to the vty\n"
2253 "The message to echo\n")
2885f72d 2254{
d62a17ae 2255 char *message;
2885f72d 2256
d62a17ae 2257 vty_out(vty, "%s\n",
2258 ((message = argv_concat(argv, argc, 1)) ? message : ""));
2259 if (message)
2260 XFREE(MTYPE_TMP, message);
2261 return CMD_SUCCESS;
2885f72d 2262}
2263
274a4a44 2264DEFUN (config_logmsg,
2265 config_logmsg_cmd,
199d90a1 2266 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
274a4a44 2267 "Send a message to enabled logging destinations\n"
2268 LOG_LEVEL_DESC
2269 "The message to send\n")
2270{
d62a17ae 2271 int idx_log_level = 1;
2272 int idx_message = 2;
2273 int level;
2274 char *message;
274a4a44 2275
d62a17ae 2276 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
2277 return CMD_ERR_NO_MATCH;
274a4a44 2278
d62a17ae 2279 zlog(level, "%s",
2280 ((message = argv_concat(argv, argc, idx_message)) ? message : ""));
2281 if (message)
2282 XFREE(MTYPE_TMP, message);
65efcfce 2283
d62a17ae 2284 return CMD_SUCCESS;
274a4a44 2285}
2286
2287DEFUN (show_logging,
2288 show_logging_cmd,
2289 "show logging",
2290 SHOW_STR
2291 "Show current logging configuration\n")
2292{
d62a17ae 2293 struct zlog *zl = zlog_default;
2294
2295 vty_out(vty, "Syslog logging: ");
2296 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
2297 vty_out(vty, "disabled");
2298 else
2299 vty_out(vty, "level %s, facility %s, ident %s",
2300 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
2301 facility_name(zl->facility), zl->ident);
2302 vty_out(vty, "\n");
2303
2304 vty_out(vty, "Stdout logging: ");
2305 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
2306 vty_out(vty, "disabled");
2307 else
2308 vty_out(vty, "level %s",
2309 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
2310 vty_out(vty, "\n");
2311
2312 vty_out(vty, "Monitor logging: ");
2313 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
2314 vty_out(vty, "disabled");
2315 else
2316 vty_out(vty, "level %s",
2317 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
2318 vty_out(vty, "\n");
2319
2320 vty_out(vty, "File logging: ");
2321 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
2322 vty_out(vty, "disabled");
2323 else
2324 vty_out(vty, "level %s, filename %s",
2325 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
2326 zl->filename);
2327 vty_out(vty, "\n");
2328
2329 vty_out(vty, "Protocol name: %s\n", zl->protoname);
2330 vty_out(vty, "Record priority: %s\n",
2331 (zl->record_priority ? "enabled" : "disabled"));
2332 vty_out(vty, "Timestamp precision: %d\n", zl->timestamp_precision);
2333
2334 return CMD_SUCCESS;
274a4a44 2335}
2336
718e3744 2337DEFUN (config_log_stdout,
2338 config_log_stdout_cmd,
6de69f83 2339 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2340 "Logging control\n"
2341 "Set stdout logging level\n"
2342 LOG_LEVEL_DESC)
2343{
d62a17ae 2344 int idx_log_level = 2;
58749582 2345
d62a17ae 2346 if (argc == idx_log_level) {
2347 zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl);
2348 return CMD_SUCCESS;
2349 }
2350 int level;
274a4a44 2351
d62a17ae 2352 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
2353 return CMD_ERR_NO_MATCH;
2354 zlog_set_level(ZLOG_DEST_STDOUT, level);
2355 return CMD_SUCCESS;
718e3744 2356}
2357
2358DEFUN (no_config_log_stdout,
2359 no_config_log_stdout_cmd,
6de69f83 2360 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 2361 NO_STR
2362 "Logging control\n"
274a4a44 2363 "Cancel logging to stdout\n"
d0bfb22c 2364 LOG_LEVEL_DESC)
718e3744 2365{
d62a17ae 2366 zlog_set_level(ZLOG_DEST_STDOUT, ZLOG_DISABLED);
2367 return CMD_SUCCESS;
718e3744 2368}
2369
274a4a44 2370DEFUN (config_log_monitor,
2371 config_log_monitor_cmd,
6de69f83 2372 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2373 "Logging control\n"
2374 "Set terminal line (monitor) logging level\n"
2375 LOG_LEVEL_DESC)
2376{
d62a17ae 2377 int idx_log_level = 2;
58749582 2378
d62a17ae 2379 if (argc == idx_log_level) {
2380 zlog_set_level(ZLOG_DEST_MONITOR, zlog_default->default_lvl);
2381 return CMD_SUCCESS;
2382 }
2383 int level;
274a4a44 2384
d62a17ae 2385 if ((level = level_match(argv[idx_log_level]->arg)) == ZLOG_DISABLED)
2386 return CMD_ERR_NO_MATCH;
2387 zlog_set_level(ZLOG_DEST_MONITOR, level);
2388 return CMD_SUCCESS;
274a4a44 2389}
2390
2391DEFUN (no_config_log_monitor,
2392 no_config_log_monitor_cmd,
6de69f83 2393 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2394 NO_STR
2395 "Logging control\n"
2396 "Disable terminal line (monitor) logging\n"
d0bfb22c 2397 LOG_LEVEL_DESC)
274a4a44 2398{
d62a17ae 2399 zlog_set_level(ZLOG_DEST_MONITOR, ZLOG_DISABLED);
2400 return CMD_SUCCESS;
274a4a44 2401}
2402
d62a17ae 2403static int set_log_file(struct vty *vty, const char *fname, int loglevel)
718e3744 2404{
d62a17ae 2405 int ret;
2406 char *p = NULL;
2407 const char *fullpath;
d0bfb22c 2408
d62a17ae 2409 /* Path detection. */
2410 if (!IS_DIRECTORY_SEP(*fname)) {
2411 char cwd[MAXPATHLEN + 1];
2412 cwd[MAXPATHLEN] = '\0';
d0bfb22c 2413
d62a17ae 2414 if (getcwd(cwd, MAXPATHLEN) == NULL) {
450971aa 2415 flog_err_sys(EC_LIB_SYSTEM_CALL,
09c866e3 2416 "config_log_file: Unable to alloc mem!");
d62a17ae 2417 return CMD_WARNING_CONFIG_FAILED;
2418 }
d0bfb22c 2419
0ce1ca80 2420 p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2);
d62a17ae 2421 sprintf(p, "%s/%s", cwd, fname);
2422 fullpath = p;
2423 } else
2424 fullpath = fname;
718e3744 2425
d62a17ae 2426 ret = zlog_set_file(fullpath, loglevel);
718e3744 2427
0a22ddfb 2428 XFREE(MTYPE_TMP, p);
9035efaa 2429
d62a17ae 2430 if (!ret) {
f8507817
DS
2431 if (vty)
2432 vty_out(vty, "can't open logfile %s\n", fname);
d62a17ae 2433 return CMD_WARNING_CONFIG_FAILED;
2434 }
718e3744 2435
0a22ddfb 2436 XFREE(MTYPE_HOST, host.logfile);
718e3744 2437
d62a17ae 2438 host.logfile = XSTRDUP(MTYPE_HOST, fname);
718e3744 2439
c05795b1 2440#if defined(HAVE_CUMULUS)
d62a17ae 2441 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
0204baa8 2442 zlog_set_level(ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
c05795b1 2443#endif
d62a17ae 2444 return CMD_SUCCESS;
718e3744 2445}
2446
e9b4e74a 2447void command_setup_early_logging(const char *dest, const char *level)
f8507817
DS
2448{
2449 char *token;
2450
e9b4e74a
DS
2451 if (level) {
2452 int nlevel = level_match(level);
2453
2454 if (nlevel != ZLOG_DISABLED)
2455 zlog_default->default_lvl = nlevel;
2456 }
2457
2458 if (!dest)
2459 return;
2460
2461 if (strcmp(dest, "stdout") == 0) {
f8507817
DS
2462 zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl);
2463 return;
2464 }
2465
e9b4e74a 2466 if (strcmp(dest, "syslog") == 0) {
f8507817
DS
2467 zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
2468 return;
2469 }
2470
e9b4e74a 2471 token = strstr(dest, ":");
74e7158c 2472 if (token == NULL)
2473 return;
2474
f8507817
DS
2475 token++;
2476
2477 set_log_file(NULL, token, zlog_default->default_lvl);
2478}
2479
274a4a44 2480DEFUN (config_log_file,
2481 config_log_file_cmd,
6de69f83 2482 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
274a4a44 2483 "Logging control\n"
2484 "Logging to file\n"
2485 "Logging filename\n"
2486 LOG_LEVEL_DESC)
2487{
d62a17ae 2488 int idx_filename = 2;
2489 int idx_log_levels = 3;
2490 if (argc == 4) {
2491 int level;
2492 if ((level = level_match(argv[idx_log_levels]->arg))
2493 == ZLOG_DISABLED)
2494 return CMD_ERR_NO_MATCH;
2495 return set_log_file(vty, argv[idx_filename]->arg, level);
2496 } else
2497 return set_log_file(vty, argv[idx_filename]->arg,
2498 zlog_default->default_lvl);
274a4a44 2499}
2500
914432b5 2501static void disable_log_file(void)
0204baa8
DW
2502{
2503 zlog_reset_file();
2504
0a22ddfb 2505 XFREE(MTYPE_HOST, host.logfile);
0204baa8
DW
2506
2507 host.logfile = NULL;
2508}
2509
718e3744 2510DEFUN (no_config_log_file,
2511 no_config_log_file_cmd,
d0bfb22c 2512 "no log file [FILENAME [LEVEL]]",
718e3744 2513 NO_STR
2514 "Logging control\n"
2515 "Cancel logging to file\n"
d0bfb22c 2516 "Logging file name\n"
d0bfb22c 2517 "Logging level\n")
718e3744 2518{
0204baa8 2519 disable_log_file();
d62a17ae 2520 return CMD_SUCCESS;
718e3744 2521}
2522
2523DEFUN (config_log_syslog,
2524 config_log_syslog_cmd,
6de69f83 2525 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
12ab19f1 2526 "Logging control\n"
274a4a44 2527 "Set syslog logging level\n"
2528 LOG_LEVEL_DESC)
2529{
d62a17ae 2530 int idx_log_levels = 2;
0204baa8 2531
d62a17ae 2532 if (argc == 3) {
2533 int level;
2534 if ((level = level_match(argv[idx_log_levels]->arg))
2535 == ZLOG_DISABLED)
2536 return CMD_ERR_NO_MATCH;
2537 zlog_set_level(ZLOG_DEST_SYSLOG, level);
2538 return CMD_SUCCESS;
2539 } else {
2540 zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
2541 return CMD_SUCCESS;
2542 }
274a4a44 2543}
2544
718e3744 2545DEFUN (no_config_log_syslog,
2546 no_config_log_syslog_cmd,
6de69f83 2547 "no log syslog [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>] [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
718e3744 2548 NO_STR
2549 "Logging control\n"
274a4a44 2550 "Cancel logging to syslog\n"
d0bfb22c
QY
2551 LOG_FACILITY_DESC
2552 LOG_LEVEL_DESC)
718e3744 2553{
d62a17ae 2554 zlog_set_level(ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
2555 return CMD_SUCCESS;
718e3744 2556}
2557
274a4a44 2558DEFUN (config_log_facility,
2559 config_log_facility_cmd,
9ccf14f7 2560 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
718e3744 2561 "Logging control\n"
274a4a44 2562 "Facility parameter for syslog messages\n"
2563 LOG_FACILITY_DESC)
718e3744 2564{
d62a17ae 2565 int idx_target = 2;
2566 int facility = facility_match(argv[idx_target]->arg);
274a4a44 2567
d62a17ae 2568 zlog_default->facility = facility;
2569 return CMD_SUCCESS;
718e3744 2570}
2571
274a4a44 2572DEFUN (no_config_log_facility,
2573 no_config_log_facility_cmd,
9ccf14f7 2574 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
718e3744 2575 NO_STR
2576 "Logging control\n"
274a4a44 2577 "Reset syslog facility to default (daemon)\n"
d0bfb22c 2578 LOG_FACILITY_DESC)
274a4a44 2579{
d62a17ae 2580 zlog_default->facility = LOG_DAEMON;
2581 return CMD_SUCCESS;
274a4a44 2582}
2583
718e3744 2584DEFUN (config_log_record_priority,
2585 config_log_record_priority_cmd,
2586 "log record-priority",
2587 "Logging control\n"
2588 "Log the priority of the message within the message\n")
2589{
d62a17ae 2590 zlog_default->record_priority = 1;
2591 return CMD_SUCCESS;
718e3744 2592}
2593
2594DEFUN (no_config_log_record_priority,
2595 no_config_log_record_priority_cmd,
2596 "no log record-priority",
2597 NO_STR
2598 "Logging control\n"
2599 "Do not log the priority of the message within the message\n")
2600{
d62a17ae 2601 zlog_default->record_priority = 0;
2602 return CMD_SUCCESS;
718e3744 2603}
2604
1ed72e0b
AS
2605DEFUN (config_log_timestamp_precision,
2606 config_log_timestamp_precision_cmd,
6147e2c6 2607 "log timestamp precision (0-6)",
1ed72e0b
AS
2608 "Logging control\n"
2609 "Timestamp configuration\n"
2610 "Set the timestamp precision\n"
2611 "Number of subsecond digits\n")
2612{
d62a17ae 2613 int idx_number = 3;
2614 zlog_default->timestamp_precision =
2615 strtoul(argv[idx_number]->arg, NULL, 10);
2616 return CMD_SUCCESS;
1ed72e0b
AS
2617}
2618
2619DEFUN (no_config_log_timestamp_precision,
2620 no_config_log_timestamp_precision_cmd,
2621 "no log timestamp precision",
2622 NO_STR
2623 "Logging control\n"
2624 "Timestamp configuration\n"
2625 "Reset the timestamp precision to the default value of 0\n")
2626{
d62a17ae 2627 zlog_default->timestamp_precision = 0;
2628 return CMD_SUCCESS;
1ed72e0b
AS
2629}
2630
9eed278b
DL
2631DEFUN (debug_memstats,
2632 debug_memstats_cmd,
2633 "[no] debug memstats-at-exit",
2634 NO_STR
2635 DEBUG_STR
2636 "Print memory type statistics at exit\n")
2637{
2638 debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
2639 return CMD_SUCCESS;
2640}
2641
d62a17ae 2642int cmd_banner_motd_file(const char *file)
7cfc61d3 2643{
d62a17ae 2644 int success = CMD_SUCCESS;
2645 char p[PATH_MAX];
2646 char *rpath;
2647 char *in;
7cfc61d3 2648
d62a17ae 2649 rpath = realpath(file, p);
2650 if (!rpath)
2651 return CMD_ERR_NO_FILE;
2652 in = strstr(rpath, SYSCONFDIR);
2653 if (in == rpath) {
0a22ddfb 2654 XFREE(MTYPE_HOST, host.motdfile);
d62a17ae 2655 host.motdfile = XSTRDUP(MTYPE_HOST, file);
2656 } else
2657 success = CMD_WARNING_CONFIG_FAILED;
1ee08155 2658
d62a17ae 2659 return success;
7cfc61d3
DS
2660}
2661
19d61463
DA
2662void cmd_banner_motd_line(const char *line)
2663{
2664 if (host.motd)
2665 XFREE(MTYPE_HOST, host.motd);
2666 host.motd = XSTRDUP(MTYPE_HOST, line);
2667}
2668
3b0c5d9a 2669DEFUN (banner_motd_file,
2670 banner_motd_file_cmd,
4d833e55 2671 "banner motd file FILE",
3b0c5d9a 2672 "Set banner\n"
2673 "Banner for motd\n"
2674 "Banner from a file\n"
2675 "Filename\n")
2676{
d62a17ae 2677 int idx_file = 3;
2678 const char *filename = argv[idx_file]->arg;
2679 int cmd = cmd_banner_motd_file(filename);
1ee08155 2680
d62a17ae 2681 if (cmd == CMD_ERR_NO_FILE)
2682 vty_out(vty, "%s does not exist", filename);
2683 else if (cmd == CMD_WARNING_CONFIG_FAILED)
2684 vty_out(vty, "%s must be in %s", filename, SYSCONFDIR);
1ee08155 2685
d62a17ae 2686 return cmd;
3b0c5d9a 2687}
718e3744 2688
19d61463
DA
2689DEFUN (banner_motd_line,
2690 banner_motd_line_cmd,
2691 "banner motd line LINE...",
2692 "Set banner\n"
2693 "Banner for motd\n"
2694 "Banner from an input\n"
2695 "Text\n")
2696{
2697 int idx = 0;
2698 char *motd;
2699
2700 argv_find(argv, argc, "LINE", &idx);
2701 motd = argv_concat(argv, argc, idx);
2702
2703 cmd_banner_motd_line(motd);
2704 XFREE(MTYPE_TMP, motd);
2705
2706 return CMD_SUCCESS;
2707}
2708
718e3744 2709DEFUN (banner_motd_default,
2710 banner_motd_default_cmd,
2711 "banner motd default",
2712 "Set banner string\n"
2713 "Strings for motd\n"
2714 "Default string\n")
2715{
19d61463 2716 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2717 return CMD_SUCCESS;
718e3744 2718}
2719
2720DEFUN (no_banner_motd,
2721 no_banner_motd_cmd,
2722 "no banner motd",
2723 NO_STR
2724 "Set banner string\n"
2725 "Strings for motd\n")
2726{
d62a17ae 2727 host.motd = NULL;
2728 if (host.motdfile)
2729 XFREE(MTYPE_HOST, host.motdfile);
2730 host.motdfile = NULL;
2731 return CMD_SUCCESS;
718e3744 2732}
2733
a83a5331
QY
2734DEFUN(find,
2735 find_cmd,
68912a20
QY
2736 "find REGEX",
2737 "Find CLI command matching a regular expression\n"
2738 "Search pattern (POSIX regex)\n")
a83a5331 2739{
68912a20 2740 char *pattern = argv[1]->arg;
cf6c83e7
QY
2741 const struct cmd_node *node;
2742 const struct cmd_element *cli;
2743 vector clis;
a83a5331 2744
68912a20
QY
2745 regex_t exp = {};
2746
2747 int cr = regcomp(&exp, pattern, REG_NOSUB | REG_EXTENDED);
2748
2749 if (cr != 0) {
2750 switch (cr) {
2751 case REG_BADBR:
2752 vty_out(vty, "%% Invalid {...} expression\n");
2753 break;
2754 case REG_BADRPT:
2755 vty_out(vty, "%% Bad repetition operator\n");
2756 break;
2757 case REG_BADPAT:
2758 vty_out(vty, "%% Regex syntax error\n");
2759 break;
2760 case REG_ECOLLATE:
2761 vty_out(vty, "%% Invalid collating element\n");
2762 break;
2763 case REG_ECTYPE:
2764 vty_out(vty, "%% Invalid character class name\n");
2765 break;
2766 case REG_EESCAPE:
2767 vty_out(vty,
2768 "%% Regex ended with escape character (\\)\n");
2769 break;
2770 case REG_ESUBREG:
2771 vty_out(vty,
2772 "%% Invalid number in \\digit construction\n");
2773 break;
2774 case REG_EBRACK:
2775 vty_out(vty, "%% Unbalanced square brackets\n");
2776 break;
2777 case REG_EPAREN:
2778 vty_out(vty, "%% Unbalanced parentheses\n");
2779 break;
2780 case REG_EBRACE:
2781 vty_out(vty, "%% Unbalanced braces\n");
2782 break;
2783 case REG_ERANGE:
2784 vty_out(vty,
2785 "%% Invalid endpoint in range expression\n");
2786 break;
2787 case REG_ESPACE:
2788 vty_out(vty, "%% Failed to compile (out of memory)\n");
2789 break;
2790 }
2791
2792 goto done;
2793 }
2794
2795
a83a5331 2796 for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
cf6c83e7 2797 node = vector_slot(cmdvec, i);
a83a5331
QY
2798 if (!node)
2799 continue;
cf6c83e7 2800 clis = node->cmd_vector;
a83a5331 2801 for (unsigned int j = 0; j < vector_active(clis); j++) {
cf6c83e7 2802 cli = vector_slot(clis, j);
68912a20
QY
2803
2804 if (regexec(&exp, cli->string, 0, NULL, 0) == 0)
cf6c83e7 2805 vty_out(vty, " (%s) %s\n",
a83a5331
QY
2806 node_names[node->node], cli->string);
2807 }
2808 }
2809
68912a20
QY
2810done:
2811 regfree(&exp);
a83a5331
QY
2812 return CMD_SUCCESS;
2813}
2814
718e3744 2815/* Set config filename. Called from vty.c */
d62a17ae 2816void host_config_set(const char *filename)
718e3744 2817{
0a22ddfb 2818 XFREE(MTYPE_HOST, host.config);
d62a17ae 2819 host.config = XSTRDUP(MTYPE_HOST, filename);
718e3744 2820}
2821
d62a17ae 2822const char *host_config_get(void)
57387fb2 2823{
d62a17ae 2824 return host.config;
57387fb2
CF
2825}
2826
d62a17ae 2827void install_default(enum node_type node)
718e3744 2828{
d62a17ae 2829 install_element(node, &config_exit_cmd);
2830 install_element(node, &config_quit_cmd);
2831 install_element(node, &config_end_cmd);
2832 install_element(node, &config_help_cmd);
2833 install_element(node, &config_list_cmd);
26fbe472 2834 install_element(node, &show_cli_graph_cmd);
a83a5331 2835 install_element(node, &find_cmd);
718e3744 2836
d62a17ae 2837 install_element(node, &config_write_cmd);
2838 install_element(node, &show_running_config_cmd);
7f059ea6 2839
d62a17ae 2840 install_element(node, &autocomplete_cmd);
1c2facd1
RW
2841
2842 nb_cli_install_default(node);
718e3744 2843}
2844
87f44e2f
DL
2845/* Initialize command interface. Install basic nodes and commands.
2846 *
2847 * terminal = 0 -- vtysh / no logging, no config control
2848 * terminal = 1 -- normal daemon
9473e340 2849 * terminal = -1 -- watchfrr / no logging, but minimal config control */
d62a17ae 2850void cmd_init(int terminal)
2851{
419cd5a0
MK
2852 struct utsname names;
2853
a83a5331
QY
2854 if (array_size(node_names) != NODE_TYPE_MAX)
2855 assert(!"Update the CLI node description array!");
2856
419cd5a0 2857 uname(&names);
d62a17ae 2858 qobj_init();
2859
fe6b47b9
QY
2860 /* register command preprocessors */
2861 hook_register(cmd_execute, handle_pipe_action);
2862 hook_register(cmd_execute_done, handle_pipe_action_done);
2863
d62a17ae 2864 varhandlers = list_new();
2865
2866 /* Allocate initial top vector of commands. */
2867 cmdvec = vector_init(VECTOR_MIN_SIZE);
2868
2869 /* Default host value settings. */
419cd5a0
MK
2870 host.name = XSTRDUP(MTYPE_HOST, names.nodename);
2871#ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
6b3ee3a0
MK
2872 if ((strcmp(names.domainname, "(none)") == 0))
2873 host.domainname = NULL;
2874 else
2875 host.domainname = XSTRDUP(MTYPE_HOST, names.domainname);
419cd5a0
MK
2876#else
2877 host.domainname = NULL;
2878#endif
d62a17ae 2879 host.password = NULL;
2880 host.enable = NULL;
2881 host.logfile = NULL;
2882 host.config = NULL;
2883 host.noconfig = (terminal < 0);
2884 host.lines = -1;
19d61463 2885 cmd_banner_motd_line(FRR_DEFAULT_MOTD);
d62a17ae 2886 host.motdfile = NULL;
2887
2888 /* Install top nodes. */
2889 install_node(&view_node, NULL);
2890 install_node(&enable_node, NULL);
2891 install_node(&auth_node, NULL);
2892 install_node(&auth_enable_node, NULL);
2893 install_node(&config_node, config_write_host);
2894
2895 /* Each node's basic commands. */
2896 install_element(VIEW_NODE, &show_version_cmd);
a83a5331
QY
2897 install_element(ENABLE_NODE, &show_startup_config_cmd);
2898
d62a17ae 2899 if (terminal) {
85a6806d
MS
2900 install_element(ENABLE_NODE, &debug_memstats_cmd);
2901
d62a17ae 2902 install_element(VIEW_NODE, &config_list_cmd);
2903 install_element(VIEW_NODE, &config_exit_cmd);
2904 install_element(VIEW_NODE, &config_quit_cmd);
2905 install_element(VIEW_NODE, &config_help_cmd);
2906 install_element(VIEW_NODE, &config_enable_cmd);
2907 install_element(VIEW_NODE, &config_terminal_length_cmd);
2908 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
2909 install_element(VIEW_NODE, &show_logging_cmd);
2910 install_element(VIEW_NODE, &show_commandtree_cmd);
2911 install_element(VIEW_NODE, &echo_cmd);
2912 install_element(VIEW_NODE, &autocomplete_cmd);
a83a5331 2913 install_element(VIEW_NODE, &find_cmd);
d62a17ae 2914
d62a17ae 2915 install_element(ENABLE_NODE, &config_end_cmd);
2916 install_element(ENABLE_NODE, &config_disable_cmd);
2917 install_element(ENABLE_NODE, &config_terminal_cmd);
2918 install_element(ENABLE_NODE, &copy_runningconf_startupconf_cmd);
2919 install_element(ENABLE_NODE, &config_write_cmd);
2920 install_element(ENABLE_NODE, &show_running_config_cmd);
d62a17ae 2921 install_element(ENABLE_NODE, &config_logmsg_cmd);
a83a5331 2922
d62a17ae 2923 install_default(CONFIG_NODE);
2924
2925 thread_cmd_init();
2926 workqueue_cmd_init();
2927 hash_cmd_init();
2928 }
2929
2930 install_element(CONFIG_NODE, &hostname_cmd);
2931 install_element(CONFIG_NODE, &no_hostname_cmd);
6b3ee3a0
MK
2932 install_element(CONFIG_NODE, &domainname_cmd);
2933 install_element(CONFIG_NODE, &no_domainname_cmd);
d62a17ae 2934
2935 if (terminal > 0) {
85a6806d
MS
2936 install_element(CONFIG_NODE, &debug_memstats_cmd);
2937
d62a17ae 2938 install_element(CONFIG_NODE, &password_cmd);
322e2d5c 2939 install_element(CONFIG_NODE, &no_password_cmd);
d62a17ae 2940 install_element(CONFIG_NODE, &enable_password_cmd);
2941 install_element(CONFIG_NODE, &no_enable_password_cmd);
2942
2943 install_element(CONFIG_NODE, &config_log_stdout_cmd);
2944 install_element(CONFIG_NODE, &no_config_log_stdout_cmd);
2945 install_element(CONFIG_NODE, &config_log_monitor_cmd);
2946 install_element(CONFIG_NODE, &no_config_log_monitor_cmd);
2947 install_element(CONFIG_NODE, &config_log_file_cmd);
2948 install_element(CONFIG_NODE, &no_config_log_file_cmd);
2949 install_element(CONFIG_NODE, &config_log_syslog_cmd);
2950 install_element(CONFIG_NODE, &no_config_log_syslog_cmd);
2951 install_element(CONFIG_NODE, &config_log_facility_cmd);
2952 install_element(CONFIG_NODE, &no_config_log_facility_cmd);
d62a17ae 2953 install_element(CONFIG_NODE, &config_log_record_priority_cmd);
2954 install_element(CONFIG_NODE,
2955 &no_config_log_record_priority_cmd);
2956 install_element(CONFIG_NODE,
2957 &config_log_timestamp_precision_cmd);
2958 install_element(CONFIG_NODE,
2959 &no_config_log_timestamp_precision_cmd);
2960 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
2961 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
2962 install_element(CONFIG_NODE, &banner_motd_default_cmd);
2963 install_element(CONFIG_NODE, &banner_motd_file_cmd);
19d61463 2964 install_element(CONFIG_NODE, &banner_motd_line_cmd);
d62a17ae 2965 install_element(CONFIG_NODE, &no_banner_motd_cmd);
2966 install_element(CONFIG_NODE, &service_terminal_length_cmd);
2967 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
2968
2969 vrf_install_commands();
2970 }
af2567b6
DL
2971
2972#ifdef DEV_BUILD
d62a17ae 2973 grammar_sandbox_init();
af2567b6 2974#endif
718e3744 2975}
228da428 2976
4d762f26 2977void cmd_terminate(void)
d62a17ae 2978{
2979 struct cmd_node *cmd_node;
2980
5d806ec6
QY
2981 hook_unregister(cmd_execute, handle_pipe_action);
2982 hook_unregister(cmd_execute_done, handle_pipe_action_done);
2983
d62a17ae 2984 if (cmdvec) {
2985 for (unsigned int i = 0; i < vector_active(cmdvec); i++)
2986 if ((cmd_node = vector_slot(cmdvec, i)) != NULL) {
2987 // deleting the graph delets the cmd_element as
2988 // well
2989 graph_delete_graph(cmd_node->cmdgraph);
2990 vector_free(cmd_node->cmd_vector);
2991 hash_clean(cmd_node->cmd_hash, NULL);
2992 hash_free(cmd_node->cmd_hash);
2993 cmd_node->cmd_hash = NULL;
2994 }
2995
2996 vector_free(cmdvec);
2997 cmdvec = NULL;
2998 }
2999
0a22ddfb
QY
3000 XFREE(MTYPE_HOST, host.name);
3001 XFREE(MTYPE_HOST, host.domainname);
3002 XFREE(MTYPE_HOST, host.password);
3003 XFREE(MTYPE_HOST, host.password_encrypt);
3004 XFREE(MTYPE_HOST, host.enable);
3005 XFREE(MTYPE_HOST, host.enable_encrypt);
3006 XFREE(MTYPE_HOST, host.logfile);
3007 XFREE(MTYPE_HOST, host.motdfile);
3008 XFREE(MTYPE_HOST, host.config);
19d61463 3009 XFREE(MTYPE_HOST, host.motd);
d62a17ae 3010
6a154c88 3011 list_delete(&varhandlers);
d62a17ae 3012 qobj_finish();
228da428 3013}