2 * CLI backend interface.
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")
10 * This file is part of GNU Zebra.
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
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.
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
33 #include <lib/version.h>
39 #include "workqueue.h"
41 #include "command_match.h"
42 #include "command_graph.h"
48 DEFINE_MTYPE(LIB
, HOST
, "Host config")
49 DEFINE_MTYPE(LIB
, STRVEC
, "String vector")
50 DEFINE_MTYPE(LIB
, COMPLETION
, "Completion item")
52 const char *node_names
[] = {
55 "auth enable", // AUTH_ENABLE_NODE,
56 "enable", // ENABLE_NODE,
57 "config", // CONFIG_NODE,
58 "service", // SERVICE_NODE,
59 "debug", // DEBUG_NODE,
60 "vrf debug", // VRF_DEBUG_NODE,
61 "vnc debug", // DEBUG_VNC_NODE,
63 "keychain", // KEYCHAIN_NODE,
64 "keychain key", // KEYCHAIN_KEY_NODE,
65 "logical-router", // LOGICALROUTER_NODE,
67 "interface", // INTERFACE_NODE,
68 "zebra", // ZEBRA_NODE,
69 "table", // TABLE_NODE,
71 "ripng", // RIPNG_NODE,
72 "babel", // BABEL_NODE,
73 "eigrp", // EIGRP_NODE,
75 "bgp vpnv4", // BGP_VPNV4_NODE,
76 "bgp vpnv6", // BGP_VPNV6_NODE,
77 "bgp ipv4 unicast", // BGP_IPV4_NODE,
78 "bgp ipv4 multicast", // BGP_IPV4M_NODE,
79 "bgp ipv4 labeled unicast", // BGP_IPV4L_NODE,
80 "bgp ipv6", // BGP_IPV6_NODE,
81 "bgp ipv6 multicast", // BGP_IPV6M_NODE,
82 "bgp ipv6 labeled unicast", // BGP_IPV6L_NODE,
83 "bgp vrf policy", // BGP_VRF_POLICY_NODE,
84 "bgp vnc defaults", // BGP_VNC_DEFAULTS_NODE,
85 "bgp vnc nve", // BGP_VNC_NVE_GROUP_NODE,
86 "bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
87 "rfp defaults", // RFP_DEFAULTS_NODE,
88 "bgp evpn", // BGP_EVPN_NODE,
90 "ospf6", // OSPF6_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,
100 "irdp", // IRDP_NODE,
101 "static ip", // IP_NODE,
102 "ipv4 access list", // ACCESS_NODE,
103 "ipv4 prefix list", // PREFIX_NODE,
104 "ipv6 access list", // ACCESS_IPV6_NODE,
105 "MAC access list", // ACCESS_MAC_NODE,
106 "ipv6 prefix list", // PREFIX_IPV6_NODE,
107 "as list", // AS_LIST_NODE,
108 "community list", // COMMUNITY_LIST_NODE,
109 "routemap", // RMAP_NODE,
110 "smux", // SMUX_NODE,
111 "dump", // DUMP_NODE,
112 "forwarding", // FORWARDING_NODE,
113 "protocol", // PROTOCOL_NODE,
114 "mpls", // MPLS_NODE,
117 "link-params", // LINK_PARAMS_NODE,
118 "bgp evpn vni", // BGP_EVPN_VNI_NODE,
122 /* Command vector which includes some level of command lists. Normally
123 each daemon maintains each own cmdvec. */
124 vector cmdvec
= NULL
;
126 /* Host information structure. */
130 * Returns host.name if any, otherwise
131 * it returns the system hostname.
133 const char *cmd_hostname_get(void)
139 * Returns unix domainname
141 const char *cmd_domainname_get(void)
143 return host
.domainname
;
146 /* Standard command node structures. */
147 static struct cmd_node auth_node
= {
148 AUTH_NODE
, "Password: ",
151 static struct cmd_node view_node
= {
155 static struct cmd_node auth_enable_node
= {
156 AUTH_ENABLE_NODE
, "Password: ",
159 static struct cmd_node enable_node
= {
163 static struct cmd_node config_node
= {CONFIG_NODE
, "%s(config)# ", 1};
165 /* Default motd string. */
166 static const char *default_motd
= FRR_DEFAULT_MOTD
;
168 static const struct facility_map
{
172 } syslog_facilities
[] = {
173 {LOG_KERN
, "kern", 1},
174 {LOG_USER
, "user", 2},
175 {LOG_MAIL
, "mail", 1},
176 {LOG_DAEMON
, "daemon", 1},
177 {LOG_AUTH
, "auth", 1},
178 {LOG_SYSLOG
, "syslog", 1},
180 {LOG_NEWS
, "news", 1},
181 {LOG_UUCP
, "uucp", 2},
182 {LOG_CRON
, "cron", 1},
186 {LOG_LOCAL0
, "local0", 6},
187 {LOG_LOCAL1
, "local1", 6},
188 {LOG_LOCAL2
, "local2", 6},
189 {LOG_LOCAL3
, "local3", 6},
190 {LOG_LOCAL4
, "local4", 6},
191 {LOG_LOCAL5
, "local5", 6},
192 {LOG_LOCAL6
, "local6", 6},
193 {LOG_LOCAL7
, "local7", 6},
197 static const char *facility_name(int facility
)
199 const struct facility_map
*fm
;
201 for (fm
= syslog_facilities
; fm
->name
; fm
++)
202 if (fm
->facility
== facility
)
207 static int facility_match(const char *str
)
209 const struct facility_map
*fm
;
211 for (fm
= syslog_facilities
; fm
->name
; fm
++)
212 if (!strncmp(str
, fm
->name
, fm
->match
))
217 static int level_match(const char *s
)
221 for (level
= 0; zlog_priority
[level
] != NULL
; level
++)
222 if (!strncmp(s
, zlog_priority
[level
], 2))
224 return ZLOG_DISABLED
;
227 /* This is called from main when a daemon is invoked with -v or --version. */
228 void print_version(const char *progname
)
230 printf("%s version %s\n", progname
, FRR_VERSION
);
231 printf("%s\n", FRR_COPYRIGHT
);
232 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
236 /* Utility function to concatenate argv argument into a single string
237 with inserting ' ' character between each argument. */
238 char *argv_concat(struct cmd_token
**argv
, int argc
, int shift
)
246 for (i
= shift
; i
< argc
; i
++)
247 len
+= strlen(argv
[i
]->arg
) + 1;
250 p
= str
= XMALLOC(MTYPE_TMP
, len
);
251 for (i
= shift
; i
< argc
; i
++) {
253 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
262 * Convenience function for accessing argv data.
266 * @param text definition snippet of the desired token
267 * @param index the starting index, and where to store the
268 * index of the found token if it exists
269 * @return 1 if found, 0 otherwise
271 int argv_find(struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
274 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
275 if ((found
= strmatch(text
, argv
[i
]->text
)))
280 static unsigned int cmd_hash_key(void *p
)
282 int size
= sizeof(p
);
284 return jhash(p
, size
, 0);
287 static int cmd_hash_cmp(const void *a
, const void *b
)
292 /* Install top node of command vector. */
293 void install_node(struct cmd_node
*node
, int (*func
)(struct vty
*))
295 vector_set_index(cmdvec
, node
->node
, node
);
297 node
->cmdgraph
= graph_new();
298 node
->cmd_vector
= vector_init(VECTOR_MIN_SIZE
);
300 struct cmd_token
*token
=
301 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
302 graph_new_node(node
->cmdgraph
, token
,
303 (void (*)(void *)) & cmd_token_del
);
304 node
->cmd_hash
= hash_create_size(16, cmd_hash_key
, cmd_hash_cmp
,
309 * Tokenizes a string, storing tokens in a vector.
310 * Whitespace is ignored.
312 * Delimiter string = " \n\r\t".
314 * @param string to tokenize
315 * @return tokenized string
317 vector
cmd_make_strvec(const char *string
)
322 char *copy
, *copystart
;
323 copystart
= copy
= XSTRDUP(MTYPE_TMP
, string
);
325 // skip leading whitespace
326 while (isspace((int)*copy
) && *copy
!= '\0')
329 // if the entire string was whitespace or a comment, return
330 if (*copy
== '\0' || *copy
== '!' || *copy
== '#') {
331 XFREE(MTYPE_TMP
, copystart
);
335 vector strvec
= vector_init(VECTOR_MIN_SIZE
);
336 const char *delim
= " \n\r\t", *tok
= NULL
;
338 tok
= strsep(©
, delim
);
340 vector_set(strvec
, XSTRDUP(MTYPE_STRVEC
, tok
));
343 XFREE(MTYPE_TMP
, copystart
);
347 /* Free allocated string vector. */
348 void cmd_free_strvec(vector v
)
356 for (i
= 0; i
< vector_active(v
); i
++)
357 if ((cp
= vector_slot(v
, i
)) != NULL
)
358 XFREE(MTYPE_STRVEC
, cp
);
363 /* Return prompt character of specified node. */
364 const char *cmd_prompt(enum node_type node
)
366 struct cmd_node
*cnode
;
368 cnode
= vector_slot(cmdvec
, node
);
369 return cnode
->prompt
;
372 /* Install a command into a node. */
373 void install_element(enum node_type ntype
, struct cmd_element
*cmd
)
375 struct cmd_node
*cnode
;
377 /* cmd_init hasn't been called */
379 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
384 cnode
= vector_lookup(cmdvec
, ntype
);
389 "\tnode %d (%s) does not exist.\n"
390 "\tplease call install_node() before install_element()\n",
391 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
395 if (hash_lookup(cnode
->cmd_hash
, cmd
) != NULL
) {
398 "\tnode %d (%s) already has this command installed.\n"
399 "\tduplicate install_element call?\n",
400 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
404 assert(hash_get(cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
406 struct graph
*graph
= graph_new();
407 struct cmd_token
*token
=
408 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
409 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
411 cmd_graph_parse(graph
, cmd
);
412 cmd_graph_names(graph
);
413 cmd_graph_merge(cnode
->cmdgraph
, graph
, +1);
414 graph_delete_graph(graph
);
416 vector_set(cnode
->cmd_vector
, cmd
);
418 if (ntype
== VIEW_NODE
)
419 install_element(ENABLE_NODE
, cmd
);
422 void uninstall_element(enum node_type ntype
, struct cmd_element
*cmd
)
424 struct cmd_node
*cnode
;
426 /* cmd_init hasn't been called */
428 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
433 cnode
= vector_lookup(cmdvec
, ntype
);
438 "\tnode %d (%s) does not exist.\n"
439 "\tplease call install_node() before uninstall_element()\n",
440 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
444 if (hash_release(cnode
->cmd_hash
, cmd
) == NULL
) {
447 "\tnode %d (%s) does not have this command installed.\n"
448 "\tduplicate uninstall_element call?\n",
449 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
453 vector_unset_value(cnode
->cmd_vector
, cmd
);
455 struct graph
*graph
= graph_new();
456 struct cmd_token
*token
=
457 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
458 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
460 cmd_graph_parse(graph
, cmd
);
461 cmd_graph_names(graph
);
462 cmd_graph_merge(cnode
->cmdgraph
, graph
, -1);
463 graph_delete_graph(graph
);
465 if (ntype
== VIEW_NODE
)
466 uninstall_element(ENABLE_NODE
, cmd
);
470 static const unsigned char itoa64
[] =
471 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
473 static void to64(char *s
, long v
, int n
)
476 *s
++ = itoa64
[v
& 0x3f];
481 static char *zencrypt(const char *passwd
)
485 char *crypt(const char *, const char *);
487 gettimeofday(&tv
, 0);
489 to64(&salt
[0], random(), 3);
490 to64(&salt
[3], tv
.tv_usec
, 3);
493 return crypt(passwd
, salt
);
496 /* This function write configuration of this host. */
497 static int config_write_host(struct vty
*vty
)
499 if (cmd_hostname_get())
500 vty_out(vty
, "hostname %s\n", cmd_hostname_get());
502 if (cmd_domainname_get())
503 vty_out(vty
, "domainname %s\n", cmd_domainname_get());
506 if (host
.password_encrypt
)
507 vty_out(vty
, "password 8 %s\n", host
.password_encrypt
);
508 if (host
.enable_encrypt
)
509 vty_out(vty
, "enable password 8 %s\n",
510 host
.enable_encrypt
);
513 vty_out(vty
, "password %s\n", host
.password
);
515 vty_out(vty
, "enable password %s\n", host
.enable
);
518 if (zlog_default
->default_lvl
!= LOG_DEBUG
) {
519 vty_out(vty
, "! N.B. The 'log trap' command is deprecated.\n");
520 vty_out(vty
, "log trap %s\n",
521 zlog_priority
[zlog_default
->default_lvl
]);
525 && (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
)) {
526 vty_out(vty
, "log file %s", host
.logfile
);
527 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
]
528 != zlog_default
->default_lvl
)
531 [zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
535 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
) {
536 vty_out(vty
, "log stdout");
537 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]
538 != zlog_default
->default_lvl
)
540 zlog_priority
[zlog_default
->maxlvl
541 [ZLOG_DEST_STDOUT
]]);
545 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
546 vty_out(vty
, "no log monitor\n");
547 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]
548 != zlog_default
->default_lvl
)
549 vty_out(vty
, "log monitor %s\n",
550 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]]);
552 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
) {
553 vty_out(vty
, "log syslog");
554 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]
555 != zlog_default
->default_lvl
)
557 zlog_priority
[zlog_default
->maxlvl
558 [ZLOG_DEST_SYSLOG
]]);
562 if (zlog_default
->facility
!= LOG_DAEMON
)
563 vty_out(vty
, "log facility %s\n",
564 facility_name(zlog_default
->facility
));
566 if (zlog_default
->record_priority
== 1)
567 vty_out(vty
, "log record-priority\n");
569 if (zlog_default
->timestamp_precision
> 0)
570 vty_out(vty
, "log timestamp precision %d\n",
571 zlog_default
->timestamp_precision
);
574 vty_out(vty
, "service advanced-vty\n");
577 vty_out(vty
, "service password-encryption\n");
580 vty_out(vty
, "service terminal-length %d\n", host
.lines
);
583 vty_out(vty
, "banner motd file %s\n", host
.motdfile
);
585 vty_out(vty
, "no banner motd\n");
587 if (debug_memstats_at_exit
)
588 vty_out(vty
, "!\ndebug memstats-at-exit\n");
593 /* Utility function for getting command graph. */
594 static struct graph
*cmd_node_graph(vector v
, enum node_type ntype
)
596 struct cmd_node
*cnode
= vector_slot(v
, ntype
);
597 return cnode
->cmdgraph
;
600 static int cmd_try_do_shortcut(enum node_type node
, char *first_word
)
602 if (first_word
!= NULL
&& node
!= AUTH_NODE
&& node
!= VIEW_NODE
603 && node
!= AUTH_ENABLE_NODE
&& 0 == strcmp("do", first_word
))
609 * Compare function for cmd_token.
610 * Used with qsort to sort command completions.
612 static int compare_completions(const void *fst
, const void *snd
)
614 struct cmd_token
*first
= *(struct cmd_token
**)fst
,
615 *secnd
= *(struct cmd_token
**)snd
;
616 return strcmp(first
->text
, secnd
->text
);
620 * Takes a list of completions returned by command_complete,
621 * dedeuplicates them based on both text and description,
622 * sorts them, and returns them as a vector.
624 * @param completions linked list of cmd_token
625 * @return deduplicated and sorted vector with
627 vector
completions_to_vec(struct list
*completions
)
629 vector comps
= vector_init(VECTOR_MIN_SIZE
);
632 struct cmd_token
*token
, *cr
= NULL
;
633 unsigned int i
, exists
;
634 for (ALL_LIST_ELEMENTS_RO(completions
, ln
, token
)) {
635 if (token
->type
== END_TKN
&& (cr
= token
))
638 // linear search for token in completions vector
640 for (i
= 0; i
< vector_active(comps
) && !exists
; i
++) {
641 struct cmd_token
*curr
= vector_slot(comps
, i
);
643 exists
= !strcmp(curr
->text
, token
->text
)
644 && !strcmp(curr
->desc
, token
->desc
);
646 exists
= !strcmp(curr
->text
, token
->text
);
647 #endif /* VTYSH_DEBUG */
651 vector_set(comps
, token
);
655 qsort(comps
->index
, vector_active(comps
), sizeof(void *),
656 &compare_completions
);
658 // make <cr> the first element, if it is present
660 vector_set_index(comps
, vector_active(comps
), NULL
);
661 memmove(comps
->index
+ 1, comps
->index
,
662 (comps
->alloced
- 1) * sizeof(void *));
663 vector_set_index(comps
, 0, cr
);
669 * Generates a vector of cmd_token representing possible completions
670 * on the current input.
672 * @param vline the vectorized input line
673 * @param vty the vty with the node to match on
674 * @param status pointer to matcher status code
675 * @return vector of struct cmd_token * with possible completions
677 static vector
cmd_complete_command_real(vector vline
, struct vty
*vty
,
680 struct list
*completions
;
681 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
683 enum matcher_rv rv
= command_complete(cmdgraph
, vline
, &completions
);
685 if (MATCHER_ERROR(rv
)) {
686 *status
= CMD_ERR_NO_MATCH
;
690 vector comps
= completions_to_vec(completions
);
691 list_delete_and_null(&completions
);
693 // set status code appropriately
694 switch (vector_active(comps
)) {
696 *status
= CMD_ERR_NO_MATCH
;
699 *status
= CMD_COMPLETE_FULL_MATCH
;
702 *status
= CMD_COMPLETE_LIST_MATCH
;
708 vector
cmd_describe_command(vector vline
, struct vty
*vty
, int *status
)
712 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
713 enum node_type onode
;
714 vector shifted_vline
;
718 vty
->node
= ENABLE_NODE
;
719 /* We can try it on enable node, cos' the vty is authenticated
722 shifted_vline
= vector_init(vector_count(vline
));
724 for (index
= 1; index
< vector_active(vline
); index
++) {
725 vector_set_index(shifted_vline
, index
- 1,
726 vector_lookup(vline
, index
));
729 ret
= cmd_complete_command_real(shifted_vline
, vty
, status
);
731 vector_free(shifted_vline
);
736 return cmd_complete_command_real(vline
, vty
, status
);
739 static struct list
*varhandlers
= NULL
;
741 void cmd_variable_complete(struct cmd_token
*token
, const char *arg
,
745 const struct cmd_variable_handler
*cvh
;
749 tmpcomps
= arg
? vector_init(VECTOR_MIN_SIZE
) : comps
;
751 for (ALL_LIST_ELEMENTS_RO(varhandlers
, ln
, cvh
)) {
752 if (cvh
->tokenname
&& strcmp(cvh
->tokenname
, token
->text
))
754 if (cvh
->varname
&& (!token
->varname
755 || strcmp(cvh
->varname
, token
->varname
)))
757 cvh
->completions(tmpcomps
, token
);
765 for (i
= vector_active(tmpcomps
); i
; i
--) {
766 char *item
= vector_slot(tmpcomps
, i
- 1);
767 if (strlen(item
) >= argsz
&& !strncmp(item
, arg
, argsz
))
768 vector_set(comps
, item
);
770 XFREE(MTYPE_COMPLETION
, item
);
772 vector_free(tmpcomps
);
775 #define AUTOCOMP_INDENT 5
777 char *cmd_variable_comp2str(vector comps
, unsigned short cols
)
780 char *buf
= XCALLOC(MTYPE_TMP
, bsz
);
781 int lc
= AUTOCOMP_INDENT
;
782 size_t cs
= AUTOCOMP_INDENT
;
784 snprintf(buf
, bsz
, "%*s", AUTOCOMP_INDENT
, "");
785 for (size_t j
= 0; j
< vector_active(comps
); j
++) {
786 char *item
= vector_slot(comps
, j
);
787 itemlen
= strlen(item
);
789 if (cs
+ itemlen
+ AUTOCOMP_INDENT
+ 3 >= bsz
)
790 buf
= XREALLOC(MTYPE_TMP
, buf
, (bsz
*= 2));
792 if (lc
+ itemlen
+ 1 >= cols
) {
793 cs
+= snprintf(&buf
[cs
], bsz
- cs
, "\n%*s",
794 AUTOCOMP_INDENT
, "");
795 lc
= AUTOCOMP_INDENT
;
798 size_t written
= snprintf(&buf
[cs
], bsz
- cs
, "%s ", item
);
801 XFREE(MTYPE_COMPLETION
, item
);
802 vector_set_index(comps
, j
, NULL
);
807 void cmd_variable_handler_register(const struct cmd_variable_handler
*cvh
)
812 for (; cvh
->completions
; cvh
++)
813 listnode_add(varhandlers
, (void *)cvh
);
816 DEFUN_HIDDEN (autocomplete
,
818 "autocomplete TYPE TEXT VARNAME",
819 "Autocompletion handler (internal, for vtysh)\n"
822 "cmd_token->varname\n")
824 struct cmd_token tok
;
825 vector comps
= vector_init(32);
828 memset(&tok
, 0, sizeof(tok
));
829 tok
.type
= atoi(argv
[1]->arg
);
830 tok
.text
= argv
[2]->arg
;
831 tok
.varname
= argv
[3]->arg
;
832 if (!strcmp(tok
.varname
, "-"))
835 cmd_variable_complete(&tok
, NULL
, comps
);
837 for (i
= 0; i
< vector_active(comps
); i
++) {
838 char *text
= vector_slot(comps
, i
);
839 vty_out(vty
, "%s\n", text
);
840 XFREE(MTYPE_COMPLETION
, text
);
848 * Generate possible tab-completions for the given input. This function only
849 * returns results that would result in a valid command if used as Readline
850 * completions (as is the case in vtysh). For instance, if the passed vline ends
851 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
853 * @param vline vectorized input line
855 * @param status location to store matcher status code in
856 * @return set of valid strings for use with Readline as tab-completions.
859 char **cmd_complete_command(vector vline
, struct vty
*vty
, int *status
)
862 int original_node
= vty
->node
;
863 vector input_line
= vector_init(vector_count(vline
));
865 // if the first token is 'do' we'll want to execute the command in the
867 int do_shortcut
= cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0));
868 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
870 // construct the input line we'll be matching on
871 unsigned int offset
= (do_shortcut
) ? 1 : 0;
872 for (unsigned index
= 0; index
+ offset
< vector_active(vline
); index
++)
873 vector_set_index(input_line
, index
,
874 vector_lookup(vline
, index
+ offset
));
876 // get token completions -- this is a copying operation
877 vector comps
= NULL
, initial_comps
;
878 initial_comps
= cmd_complete_command_real(input_line
, vty
, status
);
880 if (!MATCHER_ERROR(*status
)) {
881 assert(initial_comps
);
882 // filter out everything that is not suitable for a
884 comps
= vector_init(VECTOR_MIN_SIZE
);
885 for (unsigned int i
= 0; i
< vector_active(initial_comps
);
887 struct cmd_token
*token
= vector_slot(initial_comps
, i
);
888 if (token
->type
== WORD_TKN
)
889 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
,
891 else if (IS_VARYING_TOKEN(token
->type
)) {
892 const char *ref
= vector_lookup(
893 vline
, vector_active(vline
) - 1);
894 cmd_variable_complete(token
, ref
, comps
);
897 vector_free(initial_comps
);
899 // since we filtered results, we need to re-set status code
900 switch (vector_active(comps
)) {
902 *status
= CMD_ERR_NO_MATCH
;
905 *status
= CMD_COMPLETE_FULL_MATCH
;
908 *status
= CMD_COMPLETE_LIST_MATCH
;
911 // copy completions text into an array of char*
912 ret
= XMALLOC(MTYPE_TMP
,
913 (vector_active(comps
) + 1) * sizeof(char *));
915 for (i
= 0; i
< vector_active(comps
); i
++) {
916 ret
[i
] = vector_slot(comps
, i
);
918 // set the last element to NULL, because this array is used in
919 // a Readline completion_generator function which expects NULL
920 // as a sentinel value
924 } else if (initial_comps
)
925 vector_free(initial_comps
);
927 // comps should always be null here
930 // free the adjusted input line
931 vector_free(input_line
);
933 // reset vty->node to its original value
934 vty
->node
= original_node
;
939 /* return parent node */
940 /* MUST eventually converge on CONFIG_NODE */
941 enum node_type
node_parent(enum node_type node
)
945 assert(node
> CONFIG_NODE
);
950 case BGP_VRF_POLICY_NODE
:
951 case BGP_VNC_DEFAULTS_NODE
:
952 case BGP_VNC_NVE_GROUP_NODE
:
953 case BGP_VNC_L2_GROUP_NODE
:
963 case BGP_EVPN_VNI_NODE
:
966 case KEYCHAIN_KEY_NODE
:
969 case LINK_PARAMS_NODE
:
970 ret
= INTERFACE_NODE
;
976 case LDP_IPV4_IFACE_NODE
:
979 case LDP_IPV6_IFACE_NODE
:
982 case LDP_PSEUDOWIRE_NODE
:
983 ret
= LDP_L2VPN_NODE
;
993 /* Execute command by argument vline vector. */
994 static int cmd_execute_command_real(vector vline
, enum filter_type filter
,
996 const struct cmd_element
**cmd
)
998 struct list
*argv_list
;
999 enum matcher_rv status
;
1000 const struct cmd_element
*matched_element
= NULL
;
1002 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
1003 status
= command_match(cmdgraph
, vline
, &argv_list
, &matched_element
);
1006 *cmd
= matched_element
;
1008 // if matcher error, return corresponding CMD_ERR
1009 if (MATCHER_ERROR(status
)) {
1011 list_delete_and_null(&argv_list
);
1013 case MATCHER_INCOMPLETE
:
1014 return CMD_ERR_INCOMPLETE
;
1015 case MATCHER_AMBIGUOUS
:
1016 return CMD_ERR_AMBIGUOUS
;
1018 return CMD_ERR_NO_MATCH
;
1022 // build argv array from argv list
1023 struct cmd_token
**argv
= XMALLOC(
1024 MTYPE_TMP
, argv_list
->count
* sizeof(struct cmd_token
*));
1025 struct listnode
*ln
;
1026 struct cmd_token
*token
;
1028 for (ALL_LIST_ELEMENTS_RO(argv_list
, ln
, token
))
1031 int argc
= argv_list
->count
;
1034 if (matched_element
->daemon
)
1035 ret
= CMD_SUCCESS_DAEMON
;
1037 ret
= matched_element
->func(matched_element
, vty
, argc
, argv
);
1039 // delete list and cmd_token's in it
1040 list_delete_and_null(&argv_list
);
1041 XFREE(MTYPE_TMP
, argv
);
1047 * Execute a given command, handling things like "do ..." and checking
1048 * whether the given command might apply at a parent node if doesn't
1049 * apply for the current node.
1051 * @param vline Command line input, vector of char* where each element is
1053 * @param vty The vty context in which the command should be executed.
1054 * @param cmd Pointer where the struct cmd_element of the matched command
1055 * will be stored, if any. May be set to NULL if this info is
1057 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1058 * @return The status of the command that has been executed or an error code
1059 * as to why no command could be executed.
1061 int cmd_execute_command(vector vline
, struct vty
*vty
,
1062 const struct cmd_element
**cmd
, int vtysh
)
1064 int ret
, saved_ret
= 0;
1065 enum node_type onode
, try_node
;
1067 onode
= try_node
= vty
->node
;
1069 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
1070 vector shifted_vline
;
1073 vty
->node
= ENABLE_NODE
;
1074 /* We can try it on enable node, cos' the vty is authenticated
1077 shifted_vline
= vector_init(vector_count(vline
));
1079 for (index
= 1; index
< vector_active(vline
); index
++)
1080 vector_set_index(shifted_vline
, index
- 1,
1081 vector_lookup(vline
, index
));
1083 ret
= cmd_execute_command_real(shifted_vline
, FILTER_RELAXED
,
1086 vector_free(shifted_vline
);
1092 cmd_execute_command_real(vline
, FILTER_RELAXED
, vty
, cmd
);
1097 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1098 && ret
!= CMD_NOT_MY_INSTANCE
&& ret
!= CMD_WARNING_CONFIG_FAILED
) {
1099 /* This assumes all nodes above CONFIG_NODE are childs of
1101 while (vty
->node
> CONFIG_NODE
) {
1102 try_node
= node_parent(try_node
);
1103 vty
->node
= try_node
;
1104 ret
= cmd_execute_command_real(vline
, FILTER_RELAXED
,
1106 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
1107 || ret
== CMD_NOT_MY_INSTANCE
1108 || ret
== CMD_WARNING_CONFIG_FAILED
)
1111 /* no command succeeded, reset the vty to the original node */
1115 /* return command status for original node */
1120 * Execute a given command, matching it strictly against the current node.
1121 * This mode is used when reading config files.
1123 * @param vline Command line input, vector of char* where each element is
1125 * @param vty The vty context in which the command should be executed.
1126 * @param cmd Pointer where the struct cmd_element* of the matched command
1127 * will be stored, if any. May be set to NULL if this info is
1129 * @return The status of the command that has been executed or an error code
1130 * as to why no command could be executed.
1132 int cmd_execute_command_strict(vector vline
, struct vty
*vty
,
1133 const struct cmd_element
**cmd
)
1135 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1139 * Parse one line of config, walking up the parse tree attempting to find a
1142 * @param vty The vty context in which the command should be executed.
1143 * @param cmd Pointer where the struct cmd_element* of the match command
1144 * will be stored, if any. May be set to NULL if this info is
1146 * @param use_daemon Boolean to control whether or not we match on
1147 * CMD_SUCCESS_DAEMON
1149 * @return The status of the command that has been executed or an error code
1150 * as to why no command could be executed.
1152 int command_config_read_one_line(struct vty
*vty
,
1153 const struct cmd_element
**cmd
, int use_daemon
)
1159 vline
= cmd_make_strvec(vty
->buf
);
1161 /* In case of comment line */
1165 /* Execute configuration command : this is strict match */
1166 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1168 // Climb the tree and try the command again at each node
1169 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1170 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1171 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1172 && ret
!= CMD_NOT_MY_INSTANCE
&& ret
!= CMD_WARNING_CONFIG_FAILED
1173 && vty
->node
!= CONFIG_NODE
) {
1175 saved_node
= vty
->node
;
1177 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1178 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1179 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1180 && vty
->node
> CONFIG_NODE
) {
1181 vty
->node
= node_parent(vty
->node
);
1182 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1185 // If climbing the tree did not work then ignore the command and
1186 // stay at the same node
1187 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1188 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1189 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
) {
1190 vty
->node
= saved_node
;
1194 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1195 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1197 cmd_free_strvec(vline
);
1202 /* Configuration make from file. */
1203 int config_from_file(struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1205 int ret
, error_ret
= 0;
1208 while (fgets(vty
->buf
, VTY_BUFSIZ
, fp
)) {
1212 ret
= command_config_read_one_line(vty
, NULL
, 0);
1214 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1215 && ret
!= CMD_ERR_NOTHING_TODO
)
1226 /* Configuration from terminal */
1227 DEFUN (config_terminal
,
1228 config_terminal_cmd
,
1229 "configure terminal",
1230 "Configuration from vty interface\n"
1231 "Configuration terminal\n")
1233 if (vty_config_lock(vty
))
1234 vty
->node
= CONFIG_NODE
;
1236 vty_out(vty
, "VTY configuration is locked by other VTY\n");
1237 return CMD_WARNING_CONFIG_FAILED
;
1242 /* Enable command */
1246 "Turn on privileged mode command\n")
1248 /* If enable password is NULL, change to ENABLE_NODE */
1249 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
)
1250 || vty
->type
== VTY_SHELL_SERV
)
1251 vty
->node
= ENABLE_NODE
;
1253 vty
->node
= AUTH_ENABLE_NODE
;
1258 /* Disable command */
1262 "Turn off privileged mode command\n")
1264 if (vty
->node
== ENABLE_NODE
)
1265 vty
->node
= VIEW_NODE
;
1269 /* Down vty node level. */
1273 "Exit current mode and down to previous mode\n")
1279 void cmd_exit(struct vty
*vty
)
1281 switch (vty
->node
) {
1287 vty
->status
= VTY_CLOSE
;
1290 vty
->node
= ENABLE_NODE
;
1291 vty_config_unlock(vty
);
1293 case INTERFACE_NODE
:
1295 case LOGICALROUTER_NODE
:
1306 case LDP_L2VPN_NODE
:
1312 vty
->node
= CONFIG_NODE
;
1315 case BGP_IPV4M_NODE
:
1316 case BGP_IPV4L_NODE
:
1317 case BGP_VPNV4_NODE
:
1318 case BGP_VPNV6_NODE
:
1319 case BGP_VRF_POLICY_NODE
:
1320 case BGP_VNC_DEFAULTS_NODE
:
1321 case BGP_VNC_NVE_GROUP_NODE
:
1322 case BGP_VNC_L2_GROUP_NODE
:
1324 case BGP_IPV6M_NODE
:
1326 case BGP_IPV6L_NODE
:
1327 vty
->node
= BGP_NODE
;
1329 case BGP_EVPN_VNI_NODE
:
1330 vty
->node
= BGP_EVPN_NODE
;
1334 vty
->node
= LDP_NODE
;
1336 case LDP_IPV4_IFACE_NODE
:
1337 vty
->node
= LDP_IPV4_NODE
;
1339 case LDP_IPV6_IFACE_NODE
:
1340 vty
->node
= LDP_IPV6_NODE
;
1342 case LDP_PSEUDOWIRE_NODE
:
1343 vty
->node
= LDP_L2VPN_NODE
;
1345 case KEYCHAIN_KEY_NODE
:
1346 vty
->node
= KEYCHAIN_NODE
;
1348 case LINK_PARAMS_NODE
:
1349 vty
->node
= INTERFACE_NODE
;
1360 "Exit current mode and down to previous mode\n")
1362 return config_exit(self
, vty
, argc
, argv
);
1366 /* End of configuration. */
1370 "End current mode and change to enable mode.\n")
1372 switch (vty
->node
) {
1375 /* Nothing to do. */
1378 case INTERFACE_NODE
:
1380 case LOGICALROUTER_NODE
:
1388 case BGP_VRF_POLICY_NODE
:
1389 case BGP_VNC_DEFAULTS_NODE
:
1390 case BGP_VNC_NVE_GROUP_NODE
:
1391 case BGP_VNC_L2_GROUP_NODE
:
1392 case BGP_VPNV4_NODE
:
1393 case BGP_VPNV6_NODE
:
1395 case BGP_IPV4M_NODE
:
1396 case BGP_IPV4L_NODE
:
1398 case BGP_IPV6M_NODE
:
1400 case BGP_EVPN_VNI_NODE
:
1401 case BGP_IPV6L_NODE
:
1408 case LDP_IPV4_IFACE_NODE
:
1409 case LDP_IPV6_IFACE_NODE
:
1410 case LDP_L2VPN_NODE
:
1411 case LDP_PSEUDOWIRE_NODE
:
1414 case KEYCHAIN_KEY_NODE
:
1417 case LINK_PARAMS_NODE
:
1418 vty_config_unlock(vty
);
1419 vty
->node
= ENABLE_NODE
;
1428 DEFUN (show_version
,
1432 "Displays zebra version\n")
1434 vty_out(vty
, "%s %s (%s).\n", FRR_FULL_NAME
, FRR_VERSION
,
1435 cmd_hostname_get() ? cmd_hostname_get() : "");
1436 vty_out(vty
, "%s%s\n", FRR_COPYRIGHT
, GIT_INFO
);
1437 vty_out(vty
, "configured with:\n %s\n", FRR_CONFIG_ARGS
);
1442 /* "Set" version ... ignore version tags */
1443 DEFUN (frr_version_defaults
,
1444 frr_version_defaults_cmd
,
1445 "frr <version|defaults> LINE...",
1446 "FRRouting global parameters\n"
1447 "version configuration was written by\n"
1448 "set of configuration defaults used\n"
1454 /* Help display function for all node. */
1458 "Description of the interactive help system\n")
1461 "Quagga VTY provides advanced help feature. When you need help,\n\
1462 anytime at the command line please press '?'.\n\
1464 If nothing matches, the help list will be empty and you must backup\n\
1465 until entering a '?' shows the available options.\n\
1466 Two styles of help are provided:\n\
1467 1. Full help is available when you are ready to enter a\n\
1468 command argument (e.g. 'show ?') and describes each possible\n\
1470 2. Partial help is provided when an abbreviated argument is entered\n\
1471 and you want to know what arguments match the input\n\
1472 (e.g. 'show me?'.)\n\n");
1476 static void permute(struct graph_node
*start
, struct vty
*vty
)
1478 static struct list
*position
= NULL
;
1480 position
= list_new();
1482 struct cmd_token
*stok
= start
->data
;
1483 struct graph_node
*gnn
;
1484 struct listnode
*ln
;
1487 listnode_add(position
, start
);
1488 for (unsigned int i
= 0; i
< vector_active(start
->to
); i
++) {
1489 struct graph_node
*gn
= vector_slot(start
->to
, i
);
1490 struct cmd_token
*tok
= gn
->data
;
1491 if (tok
->attr
== CMD_ATTR_HIDDEN
1492 || tok
->attr
== CMD_ATTR_DEPRECATED
)
1494 else if (tok
->type
== END_TKN
|| gn
== start
) {
1496 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
)) {
1497 struct cmd_token
*tt
= gnn
->data
;
1498 if (tt
->type
< SPECIAL_TKN
)
1499 vty_out(vty
, " %s", tt
->text
);
1502 vty_out(vty
, "...");
1506 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1507 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
))
1516 list_delete_node(position
, listtail(position
));
1519 int cmd_list_cmds(struct vty
*vty
, int do_permute
)
1521 struct cmd_node
*node
= vector_slot(cmdvec
, vty
->node
);
1524 permute(vector_slot(node
->cmdgraph
->nodes
, 0), vty
);
1526 /* loop over all commands at this node */
1527 struct cmd_element
*element
= NULL
;
1528 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
);
1530 if ((element
= vector_slot(node
->cmd_vector
, i
))
1531 && element
->attr
!= CMD_ATTR_DEPRECATED
1532 && element
->attr
!= CMD_ATTR_HIDDEN
)
1533 vty_out(vty
, " %s\n", element
->string
);
1538 /* Help display function for all node. */
1541 "list [permutations]",
1542 "Print command list\n"
1543 "Print all possible command permutations\n")
1545 return cmd_list_cmds(vty
, argc
== 2);
1548 DEFUN (show_commandtree
,
1549 show_commandtree_cmd
,
1550 "show commandtree [permutations]",
1552 "Show command tree\n"
1553 "Permutations that we are interested in\n")
1555 return cmd_list_cmds(vty
, argc
== 3);
1558 static int vty_write_config(struct vty
*vty
)
1561 struct cmd_node
*node
;
1566 if (vty
->type
== VTY_TERM
) {
1567 vty_out(vty
, "\nCurrent configuration:\n");
1568 vty_out(vty
, "!\n");
1571 vty_out(vty
, "frr version %s\n", FRR_VER_SHORT
);
1572 vty_out(vty
, "frr defaults %s\n", DFLT_NAME
);
1573 vty_out(vty
, "!\n");
1575 for (i
= 0; i
< vector_active(cmdvec
); i
++)
1576 if ((node
= vector_slot(cmdvec
, i
)) && node
->func
1577 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
)) {
1578 if ((*node
->func
)(vty
))
1579 vty_out(vty
, "!\n");
1582 if (vty
->type
== VTY_TERM
) {
1583 vty_out(vty
, "end\n");
1589 static int file_write_config(struct vty
*vty
)
1592 char *config_file
, *slash
;
1593 char *config_file_tmp
= NULL
;
1594 char *config_file_sav
= NULL
;
1595 int ret
= CMD_WARNING
;
1596 struct vty
*file_vty
;
1597 struct stat conf_stat
;
1602 /* Check and see if we are operating under vtysh configuration */
1603 if (host
.config
== NULL
) {
1605 "Can't save to configuration file, using vtysh.\n");
1610 config_file
= host
.config
;
1613 #define O_DIRECTORY 0
1615 slash
= strrchr(config_file
, '/');
1617 char *config_dir
= XSTRDUP(MTYPE_TMP
, config_file
);
1618 config_dir
[slash
- config_file
] = '\0';
1619 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1620 XFREE(MTYPE_TMP
, config_dir
);
1622 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1623 /* if dirfd is invalid, directory sync fails, but we're still OK */
1625 config_file_sav
= XMALLOC(
1626 MTYPE_TMP
, strlen(config_file
) + strlen(CONF_BACKUP_EXT
) + 1);
1627 strcpy(config_file_sav
, config_file
);
1628 strcat(config_file_sav
, CONF_BACKUP_EXT
);
1631 config_file_tmp
= XMALLOC(MTYPE_TMP
, strlen(config_file
) + 8);
1632 sprintf(config_file_tmp
, "%s.XXXXXX", config_file
);
1634 /* Open file to configuration write. */
1635 fd
= mkstemp(config_file_tmp
);
1637 vty_out(vty
, "Can't open configuration file %s.\n",
1641 if (fchmod(fd
, CONFIGFILE_MASK
) != 0) {
1642 vty_out(vty
, "Can't chmod configuration file %s: %s (%d).\n",
1643 config_file_tmp
, safe_strerror(errno
), errno
);
1647 /* Make vty for configuration file. */
1648 file_vty
= vty_new();
1650 file_vty
->type
= VTY_FILE
;
1652 /* Config file header print. */
1653 vty_out(file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1654 vty_time_print(file_vty
, 1);
1655 vty_out(file_vty
, "!\n");
1656 vty_write_config(file_vty
);
1657 vty_close(file_vty
);
1659 if (stat(config_file
, &conf_stat
) >= 0) {
1660 if (unlink(config_file_sav
) != 0)
1661 if (errno
!= ENOENT
) {
1663 "Can't unlink backup configuration file %s.\n",
1667 if (link(config_file
, config_file_sav
) != 0) {
1669 "Can't backup old configuration file %s.\n",
1676 if (rename(config_file_tmp
, config_file
) != 0) {
1677 vty_out(vty
, "Can't save configuration file %s.\n",
1684 vty_out(vty
, "Configuration saved to %s\n", config_file
);
1688 if (ret
!= CMD_SUCCESS
)
1689 unlink(config_file_tmp
);
1692 XFREE(MTYPE_TMP
, config_file_tmp
);
1693 XFREE(MTYPE_TMP
, config_file_sav
);
1697 /* Write current configuration into file. */
1699 DEFUN (config_write
,
1701 "write [<file|memory|terminal>]",
1702 "Write running configuration to memory, network, or terminal\n"
1703 "Write to configuration file\n"
1704 "Write configuration currently in memory\n"
1705 "Write configuration to terminal\n")
1707 const int idx_type
= 1;
1709 // if command was 'write terminal' or 'write memory'
1710 if (argc
== 2 && (!strcmp(argv
[idx_type
]->text
, "terminal"))) {
1711 return vty_write_config(vty
);
1714 return file_write_config(vty
);
1717 /* ALIAS_FIXME for 'write <terminal|memory>' */
1718 DEFUN (show_running_config
,
1719 show_running_config_cmd
,
1720 "show running-config",
1722 "running configuration (same as write terminal)\n")
1724 return vty_write_config(vty
);
1727 /* ALIAS_FIXME for 'write file' */
1728 DEFUN (copy_runningconf_startupconf
,
1729 copy_runningconf_startupconf_cmd
,
1730 "copy running-config startup-config",
1731 "Copy configuration\n"
1732 "Copy running config to... \n"
1733 "Copy running config to startup config (same as write file/memory)\n")
1735 return file_write_config(vty
);
1739 /* Write startup configuration into the terminal. */
1740 DEFUN (show_startup_config
,
1741 show_startup_config_cmd
,
1742 "show startup-config",
1744 "Contents of startup configuration\n")
1751 if (host
.config
== NULL
)
1754 confp
= fopen(host
.config
, "r");
1755 if (confp
== NULL
) {
1756 vty_out(vty
, "Can't open configuration file [%s] due to '%s'\n",
1757 host
.config
, safe_strerror(errno
));
1761 while (fgets(buf
, BUFSIZ
, confp
)) {
1764 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1768 vty_out(vty
, "%s\n", buf
);
1776 int cmd_domainname_set(const char *domainname
)
1778 XFREE(MTYPE_HOST
, host
.domainname
);
1779 host
.domainname
= domainname
? XSTRDUP(MTYPE_HOST
, domainname
) : NULL
;
1783 /* Hostname configuration */
1784 DEFUN(config_domainname
,
1787 "Set system's domain name\n"
1788 "This system's domain name\n")
1790 struct cmd_token
*word
= argv
[1];
1792 if (!isalpha((int)word
->arg
[0])) {
1793 vty_out(vty
, "Please specify string starting with alphabet\n");
1794 return CMD_WARNING_CONFIG_FAILED
;
1797 return cmd_domainname_set(word
->arg
);
1800 DEFUN(config_no_domainname
,
1802 "no domainname [DOMAINNAME]",
1804 "Reset system's domain name\n"
1805 "domain name of this router\n")
1807 return cmd_domainname_set(NULL
);
1810 int cmd_hostname_set(const char *hostname
)
1812 XFREE(MTYPE_HOST
, host
.name
);
1813 host
.name
= hostname
? XSTRDUP(MTYPE_HOST
, hostname
) : NULL
;
1817 /* Hostname configuration */
1818 DEFUN (config_hostname
,
1821 "Set system's network name\n"
1822 "This system's network name\n")
1824 struct cmd_token
*word
= argv
[1];
1826 if (!isalpha((int)word
->arg
[0])) {
1827 vty_out(vty
, "Please specify string starting with alphabet\n");
1828 return CMD_WARNING_CONFIG_FAILED
;
1831 return cmd_hostname_set(word
->arg
);
1834 DEFUN (config_no_hostname
,
1836 "no hostname [HOSTNAME]",
1838 "Reset system's network name\n"
1839 "Host name of this router\n")
1841 return cmd_hostname_set(NULL
);
1844 /* VTY interface password set. */
1845 DEFUN (config_password
,
1847 "password [(8-8)] WORD",
1848 "Assign the terminal connection password\n"
1849 "Specifies a HIDDEN password will follow\n"
1850 "The password string\n")
1854 if (argc
== 3) // '8' was specified
1857 XFREE(MTYPE_HOST
, host
.password
);
1858 host
.password
= NULL
;
1859 if (host
.password_encrypt
)
1860 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1861 host
.password_encrypt
=
1862 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1866 if (!isalnum((int)argv
[idx_8
]->arg
[0])) {
1868 "Please specify string starting with alphanumeric\n");
1869 return CMD_WARNING_CONFIG_FAILED
;
1873 XFREE(MTYPE_HOST
, host
.password
);
1874 host
.password
= NULL
;
1877 if (host
.password_encrypt
)
1878 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1879 host
.password_encrypt
=
1880 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1882 host
.password
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1887 /* VTY enable password set. */
1888 DEFUN (config_enable_password
,
1889 enable_password_cmd
,
1890 "enable password [(8-8)] WORD",
1891 "Modify enable password parameters\n"
1892 "Assign the privileged level password\n"
1893 "Specifies a HIDDEN password will follow\n"
1894 "The HIDDEN 'enable' password string\n")
1899 /* Crypt type is specified. */
1901 if (argv
[idx_8
]->arg
[0] == '8') {
1903 XFREE(MTYPE_HOST
, host
.enable
);
1906 if (host
.enable_encrypt
)
1907 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1908 host
.enable_encrypt
=
1909 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1913 vty_out(vty
, "Unknown encryption type.\n");
1914 return CMD_WARNING_CONFIG_FAILED
;
1918 if (!isalnum((int)argv
[idx_8
]->arg
[0])) {
1920 "Please specify string starting with alphanumeric\n");
1921 return CMD_WARNING_CONFIG_FAILED
;
1925 XFREE(MTYPE_HOST
, host
.enable
);
1928 /* Plain password input. */
1930 if (host
.enable_encrypt
)
1931 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1932 host
.enable_encrypt
=
1933 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1935 host
.enable
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1940 /* VTY enable password delete. */
1941 DEFUN (no_config_enable_password
,
1942 no_enable_password_cmd
,
1943 "no enable password",
1945 "Modify enable password parameters\n"
1946 "Assign the privileged level password\n")
1949 XFREE(MTYPE_HOST
, host
.enable
);
1952 if (host
.enable_encrypt
)
1953 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1954 host
.enable_encrypt
= NULL
;
1959 DEFUN (service_password_encrypt
,
1960 service_password_encrypt_cmd
,
1961 "service password-encryption",
1962 "Set up miscellaneous service\n"
1963 "Enable encrypted passwords\n")
1970 if (host
.password
) {
1971 if (host
.password_encrypt
)
1972 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1973 host
.password_encrypt
=
1974 XSTRDUP(MTYPE_HOST
, zencrypt(host
.password
));
1977 if (host
.enable_encrypt
)
1978 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1979 host
.enable_encrypt
=
1980 XSTRDUP(MTYPE_HOST
, zencrypt(host
.enable
));
1986 DEFUN (no_service_password_encrypt
,
1987 no_service_password_encrypt_cmd
,
1988 "no service password-encryption",
1990 "Set up miscellaneous service\n"
1991 "Enable encrypted passwords\n")
1998 if (host
.password_encrypt
)
1999 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2000 host
.password_encrypt
= NULL
;
2002 if (host
.enable_encrypt
)
2003 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2004 host
.enable_encrypt
= NULL
;
2009 DEFUN (config_terminal_length
,
2010 config_terminal_length_cmd
,
2011 "terminal length (0-512)",
2012 "Set terminal line parameters\n"
2013 "Set number of lines on a screen\n"
2014 "Number of lines on screen (0 for no pausing)\n")
2018 vty
->lines
= atoi(argv
[idx_number
]->arg
);
2023 DEFUN (config_terminal_no_length
,
2024 config_terminal_no_length_cmd
,
2025 "terminal no length",
2026 "Set terminal line parameters\n"
2028 "Set number of lines on a screen\n")
2034 DEFUN (service_terminal_length
,
2035 service_terminal_length_cmd
,
2036 "service terminal-length (0-512)",
2037 "Set up miscellaneous service\n"
2038 "System wide terminal length configuration\n"
2039 "Number of lines of VTY (0 means no line control)\n")
2043 host
.lines
= atoi(argv
[idx_number
]->arg
);
2048 DEFUN (no_service_terminal_length
,
2049 no_service_terminal_length_cmd
,
2050 "no service terminal-length [(0-512)]",
2052 "Set up miscellaneous service\n"
2053 "System wide terminal length configuration\n"
2054 "Number of lines of VTY (0 means no line control)\n")
2060 DEFUN_HIDDEN (do_echo
,
2063 "Echo a message back to the vty\n"
2064 "The message to echo\n")
2068 vty_out(vty
, "%s\n",
2069 ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
2071 XFREE(MTYPE_TMP
, message
);
2075 DEFUN (config_logmsg
,
2077 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
2078 "Send a message to enabled logging destinations\n"
2080 "The message to send\n")
2082 int idx_log_level
= 1;
2083 int idx_message
= 2;
2087 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2088 return CMD_ERR_NO_MATCH
;
2091 ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2093 XFREE(MTYPE_TMP
, message
);
2098 DEFUN (show_logging
,
2102 "Show current logging configuration\n")
2104 struct zlog
*zl
= zlog_default
;
2106 vty_out(vty
, "Syslog logging: ");
2107 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2108 vty_out(vty
, "disabled");
2110 vty_out(vty
, "level %s, facility %s, ident %s",
2111 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2112 facility_name(zl
->facility
), zl
->ident
);
2115 vty_out(vty
, "Stdout logging: ");
2116 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2117 vty_out(vty
, "disabled");
2119 vty_out(vty
, "level %s",
2120 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2123 vty_out(vty
, "Monitor logging: ");
2124 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2125 vty_out(vty
, "disabled");
2127 vty_out(vty
, "level %s",
2128 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2131 vty_out(vty
, "File logging: ");
2132 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) || !zl
->fp
)
2133 vty_out(vty
, "disabled");
2135 vty_out(vty
, "level %s, filename %s",
2136 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2140 vty_out(vty
, "Protocol name: %s\n", zl
->protoname
);
2141 vty_out(vty
, "Record priority: %s\n",
2142 (zl
->record_priority
? "enabled" : "disabled"));
2143 vty_out(vty
, "Timestamp precision: %d\n", zl
->timestamp_precision
);
2148 DEFUN (config_log_stdout
,
2149 config_log_stdout_cmd
,
2150 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2152 "Set stdout logging level\n"
2155 int idx_log_level
= 2;
2157 if (argc
== idx_log_level
) {
2158 zlog_set_level(ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2163 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2164 return CMD_ERR_NO_MATCH
;
2165 zlog_set_level(ZLOG_DEST_STDOUT
, level
);
2169 DEFUN (no_config_log_stdout
,
2170 no_config_log_stdout_cmd
,
2171 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2174 "Cancel logging to stdout\n"
2177 zlog_set_level(ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2181 DEFUN (config_log_monitor
,
2182 config_log_monitor_cmd
,
2183 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2185 "Set terminal line (monitor) logging level\n"
2188 int idx_log_level
= 2;
2190 if (argc
== idx_log_level
) {
2191 zlog_set_level(ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2196 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2197 return CMD_ERR_NO_MATCH
;
2198 zlog_set_level(ZLOG_DEST_MONITOR
, level
);
2202 DEFUN (no_config_log_monitor
,
2203 no_config_log_monitor_cmd
,
2204 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2207 "Disable terminal line (monitor) logging\n"
2210 zlog_set_level(ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2214 static int set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2218 const char *fullpath
;
2220 /* Path detection. */
2221 if (!IS_DIRECTORY_SEP(*fname
)) {
2222 char cwd
[MAXPATHLEN
+ 1];
2223 cwd
[MAXPATHLEN
] = '\0';
2225 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
2226 zlog_err("config_log_file: Unable to alloc mem!");
2227 return CMD_WARNING_CONFIG_FAILED
;
2230 if ((p
= XMALLOC(MTYPE_TMP
, strlen(cwd
) + strlen(fname
) + 2))
2232 zlog_err("config_log_file: Unable to alloc mem!");
2233 return CMD_WARNING_CONFIG_FAILED
;
2235 sprintf(p
, "%s/%s", cwd
, fname
);
2240 ret
= zlog_set_file(fullpath
, loglevel
);
2243 XFREE(MTYPE_TMP
, p
);
2246 vty_out(vty
, "can't open logfile %s\n", fname
);
2247 return CMD_WARNING_CONFIG_FAILED
;
2251 XFREE(MTYPE_HOST
, host
.logfile
);
2253 host
.logfile
= XSTRDUP(MTYPE_HOST
, fname
);
2255 #if defined(HAVE_CUMULUS)
2256 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2257 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2262 DEFUN (config_log_file
,
2263 config_log_file_cmd
,
2264 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2267 "Logging filename\n"
2270 int idx_filename
= 2;
2271 int idx_log_levels
= 3;
2274 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2276 return CMD_ERR_NO_MATCH
;
2277 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2279 return set_log_file(vty
, argv
[idx_filename
]->arg
,
2280 zlog_default
->default_lvl
);
2283 DEFUN (no_config_log_file
,
2284 no_config_log_file_cmd
,
2285 "no log file [FILENAME [LEVEL]]",
2288 "Cancel logging to file\n"
2289 "Logging file name\n"
2295 XFREE(MTYPE_HOST
, host
.logfile
);
2297 host
.logfile
= NULL
;
2302 DEFUN (config_log_syslog
,
2303 config_log_syslog_cmd
,
2304 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2306 "Set syslog logging level\n"
2309 int idx_log_levels
= 2;
2312 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2314 return CMD_ERR_NO_MATCH
;
2315 zlog_set_level(ZLOG_DEST_SYSLOG
, level
);
2318 zlog_set_level(ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2323 DEFUN (no_config_log_syslog
,
2324 no_config_log_syslog_cmd
,
2325 "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>]",
2328 "Cancel logging to syslog\n"
2332 zlog_set_level(ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2336 DEFUN (config_log_facility
,
2337 config_log_facility_cmd
,
2338 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2340 "Facility parameter for syslog messages\n"
2344 int facility
= facility_match(argv
[idx_target
]->arg
);
2346 zlog_default
->facility
= facility
;
2350 DEFUN (no_config_log_facility
,
2351 no_config_log_facility_cmd
,
2352 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2355 "Reset syslog facility to default (daemon)\n"
2358 zlog_default
->facility
= LOG_DAEMON
;
2363 config_log_trap
, config_log_trap_cmd
,
2364 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2366 "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC
)
2371 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2372 return CMD_ERR_NO_MATCH
;
2374 zlog_default
->default_lvl
= new_level
;
2375 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2376 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2377 zlog_default
->maxlvl
[i
] = new_level
;
2382 no_config_log_trap
, no_config_log_trap_cmd
,
2383 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2386 "Permit all logging information\n" LOG_LEVEL_DESC
)
2388 zlog_default
->default_lvl
= LOG_DEBUG
;
2392 DEFUN (config_log_record_priority
,
2393 config_log_record_priority_cmd
,
2394 "log record-priority",
2396 "Log the priority of the message within the message\n")
2398 zlog_default
->record_priority
= 1;
2402 DEFUN (no_config_log_record_priority
,
2403 no_config_log_record_priority_cmd
,
2404 "no log record-priority",
2407 "Do not log the priority of the message within the message\n")
2409 zlog_default
->record_priority
= 0;
2413 DEFUN (config_log_timestamp_precision
,
2414 config_log_timestamp_precision_cmd
,
2415 "log timestamp precision (0-6)",
2417 "Timestamp configuration\n"
2418 "Set the timestamp precision\n"
2419 "Number of subsecond digits\n")
2422 zlog_default
->timestamp_precision
=
2423 strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2427 DEFUN (no_config_log_timestamp_precision
,
2428 no_config_log_timestamp_precision_cmd
,
2429 "no log timestamp precision",
2432 "Timestamp configuration\n"
2433 "Reset the timestamp precision to the default value of 0\n")
2435 zlog_default
->timestamp_precision
= 0;
2439 DEFUN (debug_memstats
,
2441 "[no] debug memstats-at-exit",
2444 "Print memory type statistics at exit\n")
2446 debug_memstats_at_exit
= !!strcmp(argv
[0]->text
, "no");
2450 int cmd_banner_motd_file(const char *file
)
2452 int success
= CMD_SUCCESS
;
2457 rpath
= realpath(file
, p
);
2459 return CMD_ERR_NO_FILE
;
2460 in
= strstr(rpath
, SYSCONFDIR
);
2463 XFREE(MTYPE_HOST
, host
.motdfile
);
2464 host
.motdfile
= XSTRDUP(MTYPE_HOST
, file
);
2466 success
= CMD_WARNING_CONFIG_FAILED
;
2471 DEFUN (banner_motd_file
,
2472 banner_motd_file_cmd
,
2473 "banner motd file FILE",
2476 "Banner from a file\n"
2480 const char *filename
= argv
[idx_file
]->arg
;
2481 int cmd
= cmd_banner_motd_file(filename
);
2483 if (cmd
== CMD_ERR_NO_FILE
)
2484 vty_out(vty
, "%s does not exist", filename
);
2485 else if (cmd
== CMD_WARNING_CONFIG_FAILED
)
2486 vty_out(vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2491 DEFUN (banner_motd_default
,
2492 banner_motd_default_cmd
,
2493 "banner motd default",
2494 "Set banner string\n"
2495 "Strings for motd\n"
2498 host
.motd
= default_motd
;
2502 DEFUN (no_banner_motd
,
2506 "Set banner string\n"
2507 "Strings for motd\n")
2511 XFREE(MTYPE_HOST
, host
.motdfile
);
2512 host
.motdfile
= NULL
;
2519 "Find CLI command containing text\n"
2520 "Text to search for\n")
2522 char *text
= argv_concat(argv
, argc
, 1);
2523 const struct cmd_node
*node
;
2524 const struct cmd_element
*cli
;
2527 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++) {
2528 node
= vector_slot(cmdvec
, i
);
2531 clis
= node
->cmd_vector
;
2532 for (unsigned int j
= 0; j
< vector_active(clis
); j
++) {
2533 cli
= vector_slot(clis
, j
);
2534 if (strcasestr(cli
->string
, text
))
2535 vty_out(vty
, " (%s) %s\n",
2536 node_names
[node
->node
], cli
->string
);
2540 XFREE(MTYPE_TMP
, text
);
2545 /* Set config filename. Called from vty.c */
2546 void host_config_set(const char *filename
)
2549 XFREE(MTYPE_HOST
, host
.config
);
2550 host
.config
= XSTRDUP(MTYPE_HOST
, filename
);
2553 const char *host_config_get(void)
2558 void install_default(enum node_type node
)
2560 install_element(node
, &config_exit_cmd
);
2561 install_element(node
, &config_quit_cmd
);
2562 install_element(node
, &config_end_cmd
);
2563 install_element(node
, &config_help_cmd
);
2564 install_element(node
, &config_list_cmd
);
2565 install_element(node
, &find_cmd
);
2567 install_element(node
, &config_write_cmd
);
2568 install_element(node
, &show_running_config_cmd
);
2570 install_element(node
, &autocomplete_cmd
);
2573 /* Initialize command interface. Install basic nodes and commands.
2575 * terminal = 0 -- vtysh / no logging, no config control
2576 * terminal = 1 -- normal daemon
2577 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2578 void cmd_init(int terminal
)
2580 struct utsname names
;
2582 if (array_size(node_names
) != NODE_TYPE_MAX
)
2583 assert(!"Update the CLI node description array!");
2588 varhandlers
= list_new();
2590 /* Allocate initial top vector of commands. */
2591 cmdvec
= vector_init(VECTOR_MIN_SIZE
);
2593 /* Default host value settings. */
2594 host
.name
= XSTRDUP(MTYPE_HOST
, names
.nodename
);
2595 #ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
2596 if ((strcmp(names
.domainname
, "(none)") == 0))
2597 host
.domainname
= NULL
;
2599 host
.domainname
= XSTRDUP(MTYPE_HOST
, names
.domainname
);
2601 host
.domainname
= NULL
;
2603 host
.password
= NULL
;
2605 host
.logfile
= NULL
;
2607 host
.noconfig
= (terminal
< 0);
2609 host
.motd
= default_motd
;
2610 host
.motdfile
= NULL
;
2612 /* Install top nodes. */
2613 install_node(&view_node
, NULL
);
2614 install_node(&enable_node
, NULL
);
2615 install_node(&auth_node
, NULL
);
2616 install_node(&auth_enable_node
, NULL
);
2617 install_node(&config_node
, config_write_host
);
2619 /* Each node's basic commands. */
2620 install_element(VIEW_NODE
, &show_version_cmd
);
2621 install_element(ENABLE_NODE
, &show_startup_config_cmd
);
2622 install_element(ENABLE_NODE
, &debug_memstats_cmd
);
2625 install_element(VIEW_NODE
, &config_list_cmd
);
2626 install_element(VIEW_NODE
, &config_exit_cmd
);
2627 install_element(VIEW_NODE
, &config_quit_cmd
);
2628 install_element(VIEW_NODE
, &config_help_cmd
);
2629 install_element(VIEW_NODE
, &config_enable_cmd
);
2630 install_element(VIEW_NODE
, &config_terminal_length_cmd
);
2631 install_element(VIEW_NODE
, &config_terminal_no_length_cmd
);
2632 install_element(VIEW_NODE
, &show_logging_cmd
);
2633 install_element(VIEW_NODE
, &show_commandtree_cmd
);
2634 install_element(VIEW_NODE
, &echo_cmd
);
2635 install_element(VIEW_NODE
, &autocomplete_cmd
);
2636 install_element(VIEW_NODE
, &find_cmd
);
2638 install_element(ENABLE_NODE
, &config_end_cmd
);
2639 install_element(ENABLE_NODE
, &config_disable_cmd
);
2640 install_element(ENABLE_NODE
, &config_terminal_cmd
);
2641 install_element(ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2642 install_element(ENABLE_NODE
, &config_write_cmd
);
2643 install_element(ENABLE_NODE
, &show_running_config_cmd
);
2644 install_element(ENABLE_NODE
, &config_logmsg_cmd
);
2646 install_default(CONFIG_NODE
);
2649 workqueue_cmd_init();
2653 install_element(CONFIG_NODE
, &hostname_cmd
);
2654 install_element(CONFIG_NODE
, &no_hostname_cmd
);
2655 install_element(CONFIG_NODE
, &domainname_cmd
);
2656 install_element(CONFIG_NODE
, &no_domainname_cmd
);
2657 install_element(CONFIG_NODE
, &frr_version_defaults_cmd
);
2658 install_element(CONFIG_NODE
, &debug_memstats_cmd
);
2661 install_element(CONFIG_NODE
, &password_cmd
);
2662 install_element(CONFIG_NODE
, &enable_password_cmd
);
2663 install_element(CONFIG_NODE
, &no_enable_password_cmd
);
2665 install_element(CONFIG_NODE
, &config_log_stdout_cmd
);
2666 install_element(CONFIG_NODE
, &no_config_log_stdout_cmd
);
2667 install_element(CONFIG_NODE
, &config_log_monitor_cmd
);
2668 install_element(CONFIG_NODE
, &no_config_log_monitor_cmd
);
2669 install_element(CONFIG_NODE
, &config_log_file_cmd
);
2670 install_element(CONFIG_NODE
, &no_config_log_file_cmd
);
2671 install_element(CONFIG_NODE
, &config_log_syslog_cmd
);
2672 install_element(CONFIG_NODE
, &no_config_log_syslog_cmd
);
2673 install_element(CONFIG_NODE
, &config_log_facility_cmd
);
2674 install_element(CONFIG_NODE
, &no_config_log_facility_cmd
);
2675 install_element(CONFIG_NODE
, &config_log_trap_cmd
);
2676 install_element(CONFIG_NODE
, &no_config_log_trap_cmd
);
2677 install_element(CONFIG_NODE
, &config_log_record_priority_cmd
);
2678 install_element(CONFIG_NODE
,
2679 &no_config_log_record_priority_cmd
);
2680 install_element(CONFIG_NODE
,
2681 &config_log_timestamp_precision_cmd
);
2682 install_element(CONFIG_NODE
,
2683 &no_config_log_timestamp_precision_cmd
);
2684 install_element(CONFIG_NODE
, &service_password_encrypt_cmd
);
2685 install_element(CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2686 install_element(CONFIG_NODE
, &banner_motd_default_cmd
);
2687 install_element(CONFIG_NODE
, &banner_motd_file_cmd
);
2688 install_element(CONFIG_NODE
, &no_banner_motd_cmd
);
2689 install_element(CONFIG_NODE
, &service_terminal_length_cmd
);
2690 install_element(CONFIG_NODE
, &no_service_terminal_length_cmd
);
2692 vrf_install_commands();
2696 grammar_sandbox_init();
2700 void cmd_terminate()
2702 struct cmd_node
*cmd_node
;
2705 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++)
2706 if ((cmd_node
= vector_slot(cmdvec
, i
)) != NULL
) {
2707 // deleting the graph delets the cmd_element as
2709 graph_delete_graph(cmd_node
->cmdgraph
);
2710 vector_free(cmd_node
->cmd_vector
);
2711 hash_clean(cmd_node
->cmd_hash
, NULL
);
2712 hash_free(cmd_node
->cmd_hash
);
2713 cmd_node
->cmd_hash
= NULL
;
2716 vector_free(cmdvec
);
2721 XFREE(MTYPE_HOST
, host
.name
);
2722 if (host
.domainname
)
2723 XFREE(MTYPE_HOST
, host
.domainname
);
2725 XFREE(MTYPE_HOST
, host
.password
);
2726 if (host
.password_encrypt
)
2727 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2729 XFREE(MTYPE_HOST
, host
.enable
);
2730 if (host
.enable_encrypt
)
2731 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2733 XFREE(MTYPE_HOST
, host
.logfile
);
2735 XFREE(MTYPE_HOST
, host
.motdfile
);
2737 XFREE(MTYPE_HOST
, host
.config
);
2739 list_delete_and_null(&varhandlers
);