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