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