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