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"
46 DEFINE_MTYPE(LIB
, HOST
, "Host config")
47 DEFINE_MTYPE(LIB
, STRVEC
, "String vector")
48 DEFINE_MTYPE(LIB
, COMPLETION
, "Completion item")
50 const char *node_names
[] = {
53 "auth enable", // AUTH_ENABLE_NODE,
54 "enable", // ENABLE_NODE,
55 "config", // CONFIG_NODE,
56 "service", // SERVICE_NODE,
57 "debug", // DEBUG_NODE,
58 "vrf debug", // VRF_DEBUG_NODE,
59 "vnc debug", // DEBUG_VNC_NODE,
61 "keychain", // KEYCHAIN_NODE,
62 "keychain key", // KEYCHAIN_KEY_NODE,
63 "logical-router", // NS_NODE,
65 "interface", // INTERFACE_NODE,
66 "zebra", // ZEBRA_NODE,
67 "table", // TABLE_NODE,
69 "ripng", // RIPNG_NODE,
70 "babel", // BABEL_NODE,
71 "eigrp", // EIGRP_NODE,
73 "bgp vpnv4", // BGP_VPNV4_NODE,
74 "bgp vpnv6", // BGP_VPNV6_NODE,
75 "bgp ipv4 unicast", // BGP_IPV4_NODE,
76 "bgp ipv4 multicast", // BGP_IPV4M_NODE,
77 "bgp ipv4 labeled unicast", // BGP_IPV4L_NODE,
78 "bgp ipv6", // BGP_IPV6_NODE,
79 "bgp ipv6 multicast", // BGP_IPV6M_NODE,
80 "bgp ipv6 labeled unicast", // BGP_IPV6L_NODE,
81 "bgp vrf policy", // BGP_VRF_POLICY_NODE,
82 "bgp vnc defaults", // BGP_VNC_DEFAULTS_NODE,
83 "bgp vnc nve", // BGP_VNC_NVE_GROUP_NODE,
84 "bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
85 "rfp defaults", // RFP_DEFAULTS_NODE,
86 "bgp evpn", // BGP_EVPN_NODE,
88 "ospf6", // OSPF6_NODE,
90 "ldp ipv4", // LDP_IPV4_NODE,
91 "ldp ipv6", // LDP_IPV6_NODE,
92 "ldp ipv4 interface", // LDP_IPV4_IFACE_NODE,
93 "ldp ipv6 interface", // LDP_IPV6_IFACE_NODE,
94 "ldp l2vpn", // LDP_L2VPN_NODE,
95 "ldp", // LDP_PSEUDOWIRE_NODE,
100 "static ip", // IP_NODE,
101 "ipv4 access list", // ACCESS_NODE,
102 "ipv4 prefix list", // PREFIX_NODE,
103 "ipv6 access list", // ACCESS_IPV6_NODE,
104 "ipv6 prefix list", // PREFIX_IPV6_NODE,
105 "as list", // AS_LIST_NODE,
106 "community list", // COMMUNITY_LIST_NODE,
107 "routemap", // RMAP_NODE,
108 "smux", // SMUX_NODE,
109 "dump", // DUMP_NODE,
110 "forwarding", // FORWARDING_NODE,
111 "protocol", // PROTOCOL_NODE,
112 "mpls", // MPLS_NODE,
114 "link-params", // LINK_PARAMS_NODE,
115 "bgp evpn vni", // BGP_EVPN_VNI_NODE,
118 /* Command vector which includes some level of command lists. Normally
119 each daemon maintains each own cmdvec. */
120 vector cmdvec
= NULL
;
122 /* Host information structure. */
125 /* Standard command node structures. */
126 static struct cmd_node auth_node
= {
127 AUTH_NODE
, "Password: ",
130 static struct cmd_node view_node
= {
134 static struct cmd_node auth_enable_node
= {
135 AUTH_ENABLE_NODE
, "Password: ",
138 static struct cmd_node enable_node
= {
142 static struct cmd_node config_node
= {CONFIG_NODE
, "%s(config)# ", 1};
144 /* Default motd string. */
145 static const char *default_motd
= FRR_DEFAULT_MOTD
;
147 static const struct facility_map
{
151 } syslog_facilities
[] = {
152 {LOG_KERN
, "kern", 1},
153 {LOG_USER
, "user", 2},
154 {LOG_MAIL
, "mail", 1},
155 {LOG_DAEMON
, "daemon", 1},
156 {LOG_AUTH
, "auth", 1},
157 {LOG_SYSLOG
, "syslog", 1},
159 {LOG_NEWS
, "news", 1},
160 {LOG_UUCP
, "uucp", 2},
161 {LOG_CRON
, "cron", 1},
165 {LOG_LOCAL0
, "local0", 6},
166 {LOG_LOCAL1
, "local1", 6},
167 {LOG_LOCAL2
, "local2", 6},
168 {LOG_LOCAL3
, "local3", 6},
169 {LOG_LOCAL4
, "local4", 6},
170 {LOG_LOCAL5
, "local5", 6},
171 {LOG_LOCAL6
, "local6", 6},
172 {LOG_LOCAL7
, "local7", 6},
176 static const char *facility_name(int facility
)
178 const struct facility_map
*fm
;
180 for (fm
= syslog_facilities
; fm
->name
; fm
++)
181 if (fm
->facility
== facility
)
186 static int facility_match(const char *str
)
188 const struct facility_map
*fm
;
190 for (fm
= syslog_facilities
; fm
->name
; fm
++)
191 if (!strncmp(str
, fm
->name
, fm
->match
))
196 static int level_match(const char *s
)
200 for (level
= 0; zlog_priority
[level
] != NULL
; level
++)
201 if (!strncmp(s
, zlog_priority
[level
], 2))
203 return ZLOG_DISABLED
;
206 /* This is called from main when a daemon is invoked with -v or --version. */
207 void print_version(const char *progname
)
209 printf("%s version %s\n", progname
, FRR_VERSION
);
210 printf("%s\n", FRR_COPYRIGHT
);
211 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
215 /* Utility function to concatenate argv argument into a single string
216 with inserting ' ' character between each argument. */
217 char *argv_concat(struct cmd_token
**argv
, int argc
, int shift
)
225 for (i
= shift
; i
< argc
; i
++)
226 len
+= strlen(argv
[i
]->arg
) + 1;
229 p
= str
= XMALLOC(MTYPE_TMP
, len
);
230 for (i
= shift
; i
< argc
; i
++) {
232 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
241 * Convenience function for accessing argv data.
245 * @param text definition snippet of the desired token
246 * @param index the starting index, and where to store the
247 * index of the found token if it exists
248 * @return 1 if found, 0 otherwise
250 int argv_find(struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
253 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
254 if ((found
= strmatch(text
, argv
[i
]->text
)))
259 static unsigned int cmd_hash_key(void *p
)
264 static int cmd_hash_cmp(const void *a
, const void *b
)
269 /* Install top node of command vector. */
270 void install_node(struct cmd_node
*node
, int (*func
)(struct vty
*))
272 vector_set_index(cmdvec
, node
->node
, node
);
274 node
->cmdgraph
= graph_new();
275 node
->cmd_vector
= vector_init(VECTOR_MIN_SIZE
);
277 struct cmd_token
*token
=
278 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
279 graph_new_node(node
->cmdgraph
, token
,
280 (void (*)(void *)) & cmd_token_del
);
281 node
->cmd_hash
= hash_create(cmd_hash_key
, cmd_hash_cmp
, NULL
);
285 * Tokenizes a string, storing tokens in a vector.
286 * Whitespace is ignored.
288 * Delimiter string = " \n\r\t".
290 * @param string to tokenize
291 * @return tokenized string
293 vector
cmd_make_strvec(const char *string
)
298 char *copy
, *copystart
;
299 copystart
= copy
= XSTRDUP(MTYPE_TMP
, string
);
301 // skip leading whitespace
302 while (isspace((int)*copy
) && *copy
!= '\0')
305 // if the entire string was whitespace or a comment, return
306 if (*copy
== '\0' || *copy
== '!' || *copy
== '#') {
307 XFREE(MTYPE_TMP
, copystart
);
311 vector strvec
= vector_init(VECTOR_MIN_SIZE
);
312 const char *delim
= " \n\r\t", *tok
= NULL
;
314 tok
= strsep(©
, delim
);
316 vector_set(strvec
, XSTRDUP(MTYPE_STRVEC
, tok
));
319 XFREE(MTYPE_TMP
, copystart
);
323 /* Free allocated string vector. */
324 void cmd_free_strvec(vector v
)
332 for (i
= 0; i
< vector_active(v
); i
++)
333 if ((cp
= vector_slot(v
, i
)) != NULL
)
334 XFREE(MTYPE_STRVEC
, cp
);
339 /* Return prompt character of specified node. */
340 const char *cmd_prompt(enum node_type node
)
342 struct cmd_node
*cnode
;
344 cnode
= vector_slot(cmdvec
, node
);
345 return cnode
->prompt
;
348 /* Install a command into a node. */
349 void install_element(enum node_type ntype
, struct cmd_element
*cmd
)
351 struct cmd_node
*cnode
;
353 /* cmd_init hasn't been called */
355 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
360 cnode
= vector_slot(cmdvec
, ntype
);
364 "Command node %d doesn't exist, please check it\n",
367 "Have you called install_node before this install_element?\n");
371 if (hash_lookup(cnode
->cmd_hash
, cmd
) != NULL
) {
373 "Multiple command installs to node %d of command:\n%s\n",
378 assert(hash_get(cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
380 struct graph
*graph
= graph_new();
381 struct cmd_token
*token
=
382 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
383 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
385 cmd_graph_parse(graph
, cmd
);
386 cmd_graph_names(graph
);
387 cmd_graph_merge(cnode
->cmdgraph
, graph
, +1);
388 graph_delete_graph(graph
);
390 vector_set(cnode
->cmd_vector
, cmd
);
392 if (ntype
== VIEW_NODE
)
393 install_element(ENABLE_NODE
, cmd
);
396 void uninstall_element(enum node_type ntype
, struct cmd_element
*cmd
)
398 struct cmd_node
*cnode
;
400 /* cmd_init hasn't been called */
402 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
407 cnode
= vector_slot(cmdvec
, ntype
);
411 "Command node %d doesn't exist, please check it\n",
414 "Have you called install_node before this install_element?\n");
418 if (hash_release(cnode
->cmd_hash
, cmd
) == NULL
) {
420 "Trying to uninstall non-installed command (node %d):\n%s\n",
425 vector_unset_value(cnode
->cmd_vector
, cmd
);
427 struct graph
*graph
= graph_new();
428 struct cmd_token
*token
=
429 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
430 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
432 cmd_graph_parse(graph
, cmd
);
433 cmd_graph_names(graph
);
434 cmd_graph_merge(cnode
->cmdgraph
, graph
, -1);
435 graph_delete_graph(graph
);
437 if (ntype
== VIEW_NODE
)
438 uninstall_element(ENABLE_NODE
, cmd
);
442 static const unsigned char itoa64
[] =
443 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
445 static void to64(char *s
, long v
, int n
)
448 *s
++ = itoa64
[v
& 0x3f];
453 static char *zencrypt(const char *passwd
)
457 char *crypt(const char *, const char *);
459 gettimeofday(&tv
, 0);
461 to64(&salt
[0], random(), 3);
462 to64(&salt
[3], tv
.tv_usec
, 3);
465 return crypt(passwd
, salt
);
468 /* This function write configuration of this host. */
469 static int config_write_host(struct vty
*vty
)
472 vty_out(vty
, "hostname %s\n", host
.name
);
475 if (host
.password_encrypt
)
476 vty_out(vty
, "password 8 %s\n", host
.password_encrypt
);
477 if (host
.enable_encrypt
)
478 vty_out(vty
, "enable password 8 %s\n",
479 host
.enable_encrypt
);
482 vty_out(vty
, "password %s\n", host
.password
);
484 vty_out(vty
, "enable password %s\n", host
.enable
);
487 if (zlog_default
->default_lvl
!= LOG_DEBUG
) {
488 vty_out(vty
, "! N.B. The 'log trap' command is deprecated.\n");
489 vty_out(vty
, "log trap %s\n",
490 zlog_priority
[zlog_default
->default_lvl
]);
494 && (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
)) {
495 vty_out(vty
, "log file %s", host
.logfile
);
496 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
]
497 != zlog_default
->default_lvl
)
500 [zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
504 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
) {
505 vty_out(vty
, "log stdout");
506 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]
507 != zlog_default
->default_lvl
)
509 zlog_priority
[zlog_default
->maxlvl
510 [ZLOG_DEST_STDOUT
]]);
514 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
515 vty_out(vty
, "no log monitor\n");
516 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]
517 != zlog_default
->default_lvl
)
518 vty_out(vty
, "log monitor %s\n",
519 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]]);
521 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
) {
522 vty_out(vty
, "log syslog");
523 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]
524 != zlog_default
->default_lvl
)
526 zlog_priority
[zlog_default
->maxlvl
527 [ZLOG_DEST_SYSLOG
]]);
531 if (zlog_default
->facility
!= LOG_DAEMON
)
532 vty_out(vty
, "log facility %s\n",
533 facility_name(zlog_default
->facility
));
535 if (zlog_default
->record_priority
== 1)
536 vty_out(vty
, "log record-priority\n");
538 if (zlog_default
->timestamp_precision
> 0)
539 vty_out(vty
, "log timestamp precision %d\n",
540 zlog_default
->timestamp_precision
);
543 vty_out(vty
, "service advanced-vty\n");
546 vty_out(vty
, "service password-encryption\n");
549 vty_out(vty
, "service terminal-length %d\n", host
.lines
);
552 vty_out(vty
, "banner motd file %s\n", host
.motdfile
);
554 vty_out(vty
, "no banner motd\n");
559 /* Utility function for getting command graph. */
560 static struct graph
*cmd_node_graph(vector v
, enum node_type ntype
)
562 struct cmd_node
*cnode
= vector_slot(v
, ntype
);
563 return cnode
->cmdgraph
;
566 static int cmd_try_do_shortcut(enum node_type node
, char *first_word
)
568 if (first_word
!= NULL
&& node
!= AUTH_NODE
&& node
!= VIEW_NODE
569 && node
!= AUTH_ENABLE_NODE
&& 0 == strcmp("do", first_word
))
575 * Compare function for cmd_token.
576 * Used with qsort to sort command completions.
578 static int compare_completions(const void *fst
, const void *snd
)
580 struct cmd_token
*first
= *(struct cmd_token
**)fst
,
581 *secnd
= *(struct cmd_token
**)snd
;
582 return strcmp(first
->text
, secnd
->text
);
586 * Takes a list of completions returned by command_complete,
587 * dedeuplicates them based on both text and description,
588 * sorts them, and returns them as a vector.
590 * @param completions linked list of cmd_token
591 * @return deduplicated and sorted vector with
593 vector
completions_to_vec(struct list
*completions
)
595 vector comps
= vector_init(VECTOR_MIN_SIZE
);
598 struct cmd_token
*token
, *cr
= NULL
;
599 unsigned int i
, exists
;
600 for (ALL_LIST_ELEMENTS_RO(completions
, ln
, token
)) {
601 if (token
->type
== END_TKN
&& (cr
= token
))
604 // linear search for token in completions vector
606 for (i
= 0; i
< vector_active(comps
) && !exists
; i
++) {
607 struct cmd_token
*curr
= vector_slot(comps
, i
);
609 exists
= !strcmp(curr
->text
, token
->text
)
610 && !strcmp(curr
->desc
, token
->desc
);
612 exists
= !strcmp(curr
->text
, token
->text
);
613 #endif /* VTYSH_DEBUG */
617 vector_set(comps
, token
);
621 qsort(comps
->index
, vector_active(comps
), sizeof(void *),
622 &compare_completions
);
624 // make <cr> the first element, if it is present
626 vector_set_index(comps
, vector_active(comps
), NULL
);
627 memmove(comps
->index
+ 1, comps
->index
,
628 (comps
->alloced
- 1) * sizeof(void *));
629 vector_set_index(comps
, 0, cr
);
635 * Generates a vector of cmd_token representing possible completions
636 * on the current input.
638 * @param vline the vectorized input line
639 * @param vty the vty with the node to match on
640 * @param status pointer to matcher status code
641 * @return vector of struct cmd_token * with possible completions
643 static vector
cmd_complete_command_real(vector vline
, struct vty
*vty
,
646 struct list
*completions
;
647 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
649 enum matcher_rv rv
= command_complete(cmdgraph
, vline
, &completions
);
651 if (MATCHER_ERROR(rv
)) {
652 *status
= CMD_ERR_NO_MATCH
;
656 vector comps
= completions_to_vec(completions
);
657 list_delete(completions
);
659 // set status code appropriately
660 switch (vector_active(comps
)) {
662 *status
= CMD_ERR_NO_MATCH
;
665 *status
= CMD_COMPLETE_FULL_MATCH
;
668 *status
= CMD_COMPLETE_LIST_MATCH
;
674 vector
cmd_describe_command(vector vline
, struct vty
*vty
, int *status
)
678 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
679 enum node_type onode
;
680 vector shifted_vline
;
684 vty
->node
= ENABLE_NODE
;
685 /* We can try it on enable node, cos' the vty is authenticated
688 shifted_vline
= vector_init(vector_count(vline
));
690 for (index
= 1; index
< vector_active(vline
); index
++) {
691 vector_set_index(shifted_vline
, index
- 1,
692 vector_lookup(vline
, index
));
695 ret
= cmd_complete_command_real(shifted_vline
, vty
, status
);
697 vector_free(shifted_vline
);
702 return cmd_complete_command_real(vline
, vty
, status
);
705 static struct list
*varhandlers
= NULL
;
707 void cmd_variable_complete(struct cmd_token
*token
, const char *arg
,
711 const struct cmd_variable_handler
*cvh
;
715 tmpcomps
= arg
? vector_init(VECTOR_MIN_SIZE
) : comps
;
717 for (ALL_LIST_ELEMENTS_RO(varhandlers
, ln
, cvh
)) {
718 if (cvh
->tokenname
&& strcmp(cvh
->tokenname
, token
->text
))
720 if (cvh
->varname
&& (!token
->varname
721 || strcmp(cvh
->varname
, token
->varname
)))
723 cvh
->completions(tmpcomps
, token
);
731 for (i
= vector_active(tmpcomps
); i
; i
--) {
732 char *item
= vector_slot(tmpcomps
, i
- 1);
733 if (strlen(item
) >= argsz
&& !strncmp(item
, arg
, argsz
))
734 vector_set(comps
, item
);
736 XFREE(MTYPE_COMPLETION
, item
);
738 vector_free(tmpcomps
);
741 #define AUTOCOMP_INDENT 5
743 char *cmd_variable_comp2str(vector comps
, unsigned short cols
)
746 char *buf
= XCALLOC(MTYPE_TMP
, bsz
);
747 int lc
= AUTOCOMP_INDENT
;
748 size_t cs
= AUTOCOMP_INDENT
;
750 snprintf(buf
, bsz
, "%*s", AUTOCOMP_INDENT
, "");
751 for (size_t j
= 0; j
< vector_active(comps
); j
++) {
752 char *item
= vector_slot(comps
, j
);
753 itemlen
= strlen(item
);
755 if (cs
+ itemlen
+ AUTOCOMP_INDENT
+ 3 >= bsz
)
756 buf
= XREALLOC(MTYPE_TMP
, buf
, (bsz
*= 2));
758 if (lc
+ itemlen
+ 1 >= cols
) {
759 cs
+= snprintf(&buf
[cs
], bsz
- cs
, "\n%*s",
760 AUTOCOMP_INDENT
, "");
761 lc
= AUTOCOMP_INDENT
;
764 size_t written
= snprintf(&buf
[cs
], bsz
- cs
, "%s ", item
);
767 XFREE(MTYPE_COMPLETION
, item
);
768 vector_set_index(comps
, j
, NULL
);
773 void cmd_variable_handler_register(const struct cmd_variable_handler
*cvh
)
778 for (; cvh
->completions
; cvh
++)
779 listnode_add(varhandlers
, (void *)cvh
);
782 DEFUN_HIDDEN (autocomplete
,
784 "autocomplete TYPE TEXT VARNAME",
785 "Autocompletion handler (internal, for vtysh)\n"
788 "cmd_token->varname\n")
790 struct cmd_token tok
;
791 vector comps
= vector_init(32);
794 memset(&tok
, 0, sizeof(tok
));
795 tok
.type
= atoi(argv
[1]->arg
);
796 tok
.text
= argv
[2]->arg
;
797 tok
.varname
= argv
[3]->arg
;
798 if (!strcmp(tok
.varname
, "-"))
801 cmd_variable_complete(&tok
, NULL
, comps
);
803 for (i
= 0; i
< vector_active(comps
); i
++) {
804 char *text
= vector_slot(comps
, i
);
805 vty_out(vty
, "%s\n", text
);
806 XFREE(MTYPE_COMPLETION
, text
);
814 * Generate possible tab-completions for the given input. This function only
815 * returns results that would result in a valid command if used as Readline
816 * completions (as is the case in vtysh). For instance, if the passed vline ends
817 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
819 * @param vline vectorized input line
821 * @param status location to store matcher status code in
822 * @return set of valid strings for use with Readline as tab-completions.
825 char **cmd_complete_command(vector vline
, struct vty
*vty
, int *status
)
828 int original_node
= vty
->node
;
829 vector input_line
= vector_init(vector_count(vline
));
831 // if the first token is 'do' we'll want to execute the command in the
833 int do_shortcut
= cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0));
834 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
836 // construct the input line we'll be matching on
837 unsigned int offset
= (do_shortcut
) ? 1 : 0;
838 for (unsigned index
= 0; index
+ offset
< vector_active(vline
); index
++)
839 vector_set_index(input_line
, index
,
840 vector_lookup(vline
, index
+ offset
));
842 // get token completions -- this is a copying operation
843 vector comps
= NULL
, initial_comps
;
844 initial_comps
= cmd_complete_command_real(input_line
, vty
, status
);
846 if (!MATCHER_ERROR(*status
)) {
847 assert(initial_comps
);
848 // filter out everything that is not suitable for a
850 comps
= vector_init(VECTOR_MIN_SIZE
);
851 for (unsigned int i
= 0; i
< vector_active(initial_comps
);
853 struct cmd_token
*token
= vector_slot(initial_comps
, i
);
854 if (token
->type
== WORD_TKN
)
855 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
,
857 else if (IS_VARYING_TOKEN(token
->type
)) {
858 const char *ref
= vector_lookup(
859 vline
, vector_active(vline
) - 1);
860 cmd_variable_complete(token
, ref
, comps
);
863 vector_free(initial_comps
);
865 // since we filtered results, we need to re-set status code
866 switch (vector_active(comps
)) {
868 *status
= CMD_ERR_NO_MATCH
;
871 *status
= CMD_COMPLETE_FULL_MATCH
;
874 *status
= CMD_COMPLETE_LIST_MATCH
;
877 // copy completions text into an array of char*
878 ret
= XMALLOC(MTYPE_TMP
,
879 (vector_active(comps
) + 1) * sizeof(char *));
881 for (i
= 0; i
< vector_active(comps
); i
++) {
882 ret
[i
] = vector_slot(comps
, i
);
884 // set the last element to NULL, because this array is used in
885 // a Readline completion_generator function which expects NULL
886 // as a sentinel value
890 } else if (initial_comps
)
891 vector_free(initial_comps
);
893 // comps should always be null here
896 // free the adjusted input line
897 vector_free(input_line
);
899 // reset vty->node to its original value
900 vty
->node
= original_node
;
905 /* return parent node */
906 /* MUST eventually converge on CONFIG_NODE */
907 enum node_type
node_parent(enum node_type node
)
911 assert(node
> CONFIG_NODE
);
916 case BGP_VRF_POLICY_NODE
:
917 case BGP_VNC_DEFAULTS_NODE
:
918 case BGP_VNC_NVE_GROUP_NODE
:
919 case BGP_VNC_L2_GROUP_NODE
:
929 case BGP_EVPN_VNI_NODE
:
932 case KEYCHAIN_KEY_NODE
:
935 case LINK_PARAMS_NODE
:
936 ret
= INTERFACE_NODE
;
942 case LDP_IPV4_IFACE_NODE
:
945 case LDP_IPV6_IFACE_NODE
:
948 case LDP_PSEUDOWIRE_NODE
:
949 ret
= LDP_L2VPN_NODE
;
959 /* Execute command by argument vline vector. */
960 static int cmd_execute_command_real(vector vline
, enum filter_type filter
,
962 const struct cmd_element
**cmd
)
964 struct list
*argv_list
;
965 enum matcher_rv status
;
966 const struct cmd_element
*matched_element
= NULL
;
968 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
969 status
= command_match(cmdgraph
, vline
, &argv_list
, &matched_element
);
972 *cmd
= matched_element
;
974 // if matcher error, return corresponding CMD_ERR
975 if (MATCHER_ERROR(status
)) {
977 list_delete(argv_list
);
979 case MATCHER_INCOMPLETE
:
980 return CMD_ERR_INCOMPLETE
;
981 case MATCHER_AMBIGUOUS
:
982 return CMD_ERR_AMBIGUOUS
;
984 return CMD_ERR_NO_MATCH
;
988 // build argv array from argv list
989 struct cmd_token
**argv
= XMALLOC(
990 MTYPE_TMP
, argv_list
->count
* sizeof(struct cmd_token
*));
992 struct cmd_token
*token
;
994 for (ALL_LIST_ELEMENTS_RO(argv_list
, ln
, token
))
997 int argc
= argv_list
->count
;
1000 if (matched_element
->daemon
)
1001 ret
= CMD_SUCCESS_DAEMON
;
1003 ret
= matched_element
->func(matched_element
, vty
, argc
, argv
);
1005 // delete list and cmd_token's in it
1006 list_delete(argv_list
);
1007 XFREE(MTYPE_TMP
, argv
);
1013 * Execute a given command, handling things like "do ..." and checking
1014 * whether the given command might apply at a parent node if doesn't
1015 * apply for the current node.
1017 * @param vline Command line input, vector of char* where each element is
1019 * @param vty The vty context in which the command should be executed.
1020 * @param cmd Pointer where the struct cmd_element of the matched command
1021 * will be stored, if any. May be set to NULL if this info is
1023 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1024 * @return The status of the command that has been executed or an error code
1025 * as to why no command could be executed.
1027 int cmd_execute_command(vector vline
, struct vty
*vty
,
1028 const struct cmd_element
**cmd
, int vtysh
)
1030 int ret
, saved_ret
= 0;
1031 enum node_type onode
, try_node
;
1033 onode
= try_node
= vty
->node
;
1035 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
1036 vector shifted_vline
;
1039 vty
->node
= ENABLE_NODE
;
1040 /* We can try it on enable node, cos' the vty is authenticated
1043 shifted_vline
= vector_init(vector_count(vline
));
1045 for (index
= 1; index
< vector_active(vline
); index
++)
1046 vector_set_index(shifted_vline
, index
- 1,
1047 vector_lookup(vline
, index
));
1049 ret
= cmd_execute_command_real(shifted_vline
, FILTER_RELAXED
,
1052 vector_free(shifted_vline
);
1058 cmd_execute_command_real(vline
, FILTER_RELAXED
, vty
, cmd
);
1063 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
) {
1064 /* This assumes all nodes above CONFIG_NODE are childs of
1066 while (vty
->node
> CONFIG_NODE
) {
1067 try_node
= node_parent(try_node
);
1068 vty
->node
= try_node
;
1069 ret
= cmd_execute_command_real(vline
, FILTER_RELAXED
,
1071 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
1074 /* no command succeeded, reset the vty to the original node */
1078 /* return command status for original node */
1083 * Execute a given command, matching it strictly against the current node.
1084 * This mode is used when reading config files.
1086 * @param vline Command line input, vector of char* where each element is
1088 * @param vty The vty context in which the command should be executed.
1089 * @param cmd Pointer where the struct cmd_element* of the matched command
1090 * will be stored, if any. May be set to NULL if this info is
1092 * @return The status of the command that has been executed or an error code
1093 * as to why no command could be executed.
1095 int cmd_execute_command_strict(vector vline
, struct vty
*vty
,
1096 const struct cmd_element
**cmd
)
1098 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1102 * Parse one line of config, walking up the parse tree attempting to find a
1105 * @param vty The vty context in which the command should be executed.
1106 * @param cmd Pointer where the struct cmd_element* of the match command
1107 * will be stored, if any. May be set to NULL if this info is
1109 * @param use_daemon Boolean to control whether or not we match on
1110 * CMD_SUCCESS_DAEMON
1112 * @return The status of the command that has been executed or an error code
1113 * as to why no command could be executed.
1115 int command_config_read_one_line(struct vty
*vty
,
1116 const struct cmd_element
**cmd
, int use_daemon
)
1122 vline
= cmd_make_strvec(vty
->buf
);
1124 /* In case of comment line */
1128 /* Execute configuration command : this is strict match */
1129 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1131 // Climb the tree and try the command again at each node
1132 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1133 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1134 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1135 && vty
->node
!= CONFIG_NODE
) {
1137 saved_node
= vty
->node
;
1139 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1140 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1141 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1142 && vty
->node
> CONFIG_NODE
) {
1143 vty
->node
= node_parent(vty
->node
);
1144 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1147 // If climbing the tree did not work then ignore the command and
1148 // stay at the same node
1149 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1150 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1151 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
) {
1152 vty
->node
= saved_node
;
1156 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1157 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1159 cmd_free_strvec(vline
);
1164 /* Configuration make from file. */
1165 int config_from_file(struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1167 int ret
, error_ret
= 0;
1170 while (fgets(vty
->buf
, VTY_BUFSIZ
, fp
)) {
1174 ret
= command_config_read_one_line(vty
, NULL
, 0);
1176 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1177 && ret
!= CMD_ERR_NOTHING_TODO
)
1188 /* Configuration from terminal */
1189 DEFUN (config_terminal
,
1190 config_terminal_cmd
,
1191 "configure terminal",
1192 "Configuration from vty interface\n"
1193 "Configuration terminal\n")
1195 if (vty_config_lock(vty
))
1196 vty
->node
= CONFIG_NODE
;
1198 vty_out(vty
, "VTY configuration is locked by other VTY\n");
1199 return CMD_WARNING_CONFIG_FAILED
;
1204 /* Enable command */
1208 "Turn on privileged mode command\n")
1210 /* If enable password is NULL, change to ENABLE_NODE */
1211 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
)
1212 || vty
->type
== VTY_SHELL_SERV
)
1213 vty
->node
= ENABLE_NODE
;
1215 vty
->node
= AUTH_ENABLE_NODE
;
1220 /* Disable command */
1224 "Turn off privileged mode command\n")
1226 if (vty
->node
== ENABLE_NODE
)
1227 vty
->node
= VIEW_NODE
;
1231 /* Down vty node level. */
1235 "Exit current mode and down to previous mode\n")
1241 void cmd_exit(struct vty
*vty
)
1243 switch (vty
->node
) {
1249 vty
->status
= VTY_CLOSE
;
1252 vty
->node
= ENABLE_NODE
;
1253 vty_config_unlock(vty
);
1255 case INTERFACE_NODE
:
1267 case LDP_L2VPN_NODE
:
1274 vty
->node
= CONFIG_NODE
;
1277 case BGP_IPV4M_NODE
:
1278 case BGP_IPV4L_NODE
:
1279 case BGP_VPNV4_NODE
:
1280 case BGP_VPNV6_NODE
:
1281 case BGP_VRF_POLICY_NODE
:
1282 case BGP_VNC_DEFAULTS_NODE
:
1283 case BGP_VNC_NVE_GROUP_NODE
:
1284 case BGP_VNC_L2_GROUP_NODE
:
1286 case BGP_IPV6M_NODE
:
1288 case BGP_IPV6L_NODE
:
1289 vty
->node
= BGP_NODE
;
1291 case BGP_EVPN_VNI_NODE
:
1292 vty
->node
= BGP_EVPN_NODE
;
1296 vty
->node
= LDP_NODE
;
1298 case LDP_IPV4_IFACE_NODE
:
1299 vty
->node
= LDP_IPV4_NODE
;
1301 case LDP_IPV6_IFACE_NODE
:
1302 vty
->node
= LDP_IPV6_NODE
;
1304 case LDP_PSEUDOWIRE_NODE
:
1305 vty
->node
= LDP_L2VPN_NODE
;
1307 case KEYCHAIN_KEY_NODE
:
1308 vty
->node
= KEYCHAIN_NODE
;
1310 case LINK_PARAMS_NODE
:
1311 vty
->node
= INTERFACE_NODE
;
1322 "Exit current mode and down to previous mode\n")
1324 return config_exit(self
, vty
, argc
, argv
);
1328 /* End of configuration. */
1332 "End current mode and change to enable mode.")
1334 switch (vty
->node
) {
1337 /* Nothing to do. */
1340 case INTERFACE_NODE
:
1349 case BGP_VRF_POLICY_NODE
:
1350 case BGP_VNC_DEFAULTS_NODE
:
1351 case BGP_VNC_NVE_GROUP_NODE
:
1352 case BGP_VNC_L2_GROUP_NODE
:
1353 case BGP_VPNV4_NODE
:
1354 case BGP_VPNV6_NODE
:
1356 case BGP_IPV4M_NODE
:
1357 case BGP_IPV4L_NODE
:
1359 case BGP_IPV6M_NODE
:
1361 case BGP_EVPN_VNI_NODE
:
1362 case BGP_IPV6L_NODE
:
1369 case LDP_IPV4_IFACE_NODE
:
1370 case LDP_IPV6_IFACE_NODE
:
1371 case LDP_L2VPN_NODE
:
1372 case LDP_PSEUDOWIRE_NODE
:
1375 case KEYCHAIN_KEY_NODE
:
1379 case LINK_PARAMS_NODE
:
1380 vty_config_unlock(vty
);
1381 vty
->node
= ENABLE_NODE
;
1390 DEFUN (show_version
,
1394 "Displays zebra version\n")
1396 vty_out(vty
, "%s %s (%s).\n", FRR_FULL_NAME
, FRR_VERSION
,
1397 host
.name
? host
.name
: "");
1398 vty_out(vty
, "%s%s\n", FRR_COPYRIGHT
, GIT_INFO
);
1399 vty_out(vty
, "configured with:\n %s\n", FRR_CONFIG_ARGS
);
1404 /* "Set" version ... ignore version tags */
1405 DEFUN (frr_version_defaults
,
1406 frr_version_defaults_cmd
,
1407 "frr <version|defaults> LINE...",
1408 "FRRouting global parameters\n"
1409 "version configuration was written by\n"
1410 "set of configuration defaults used\n"
1416 /* Help display function for all node. */
1420 "Description of the interactive help system\n")
1423 "Quagga VTY provides advanced help feature. When you need help,\n\
1424 anytime at the command line please press '?'.\n\
1426 If nothing matches, the help list will be empty and you must backup\n\
1427 until entering a '?' shows the available options.\n\
1428 Two styles of help are provided:\n\
1429 1. Full help is available when you are ready to enter a\n\
1430 command argument (e.g. 'show ?') and describes each possible\n\
1432 2. Partial help is provided when an abbreviated argument is entered\n\
1433 and you want to know what arguments match the input\n\
1434 (e.g. 'show me?'.)\n\n");
1438 static void permute(struct graph_node
*start
, struct vty
*vty
)
1440 static struct list
*position
= NULL
;
1442 position
= list_new();
1444 struct cmd_token
*stok
= start
->data
;
1445 struct graph_node
*gnn
;
1446 struct listnode
*ln
;
1449 listnode_add(position
, start
);
1450 for (unsigned int i
= 0; i
< vector_active(start
->to
); i
++) {
1451 struct graph_node
*gn
= vector_slot(start
->to
, i
);
1452 struct cmd_token
*tok
= gn
->data
;
1453 if (tok
->attr
== CMD_ATTR_HIDDEN
1454 || tok
->attr
== CMD_ATTR_DEPRECATED
)
1456 else if (tok
->type
== END_TKN
|| gn
== start
) {
1458 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
)) {
1459 struct cmd_token
*tt
= gnn
->data
;
1460 if (tt
->type
< SPECIAL_TKN
)
1461 vty_out(vty
, " %s", tt
->text
);
1464 vty_out(vty
, "...");
1468 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1469 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
))
1478 list_delete_node(position
, listtail(position
));
1481 int cmd_list_cmds(struct vty
*vty
, int do_permute
)
1483 struct cmd_node
*node
= vector_slot(cmdvec
, vty
->node
);
1486 permute(vector_slot(node
->cmdgraph
->nodes
, 0), vty
);
1488 /* loop over all commands at this node */
1489 struct cmd_element
*element
= NULL
;
1490 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
);
1492 if ((element
= vector_slot(node
->cmd_vector
, i
))
1493 && element
->attr
!= CMD_ATTR_DEPRECATED
1494 && element
->attr
!= CMD_ATTR_HIDDEN
)
1495 vty_out(vty
, " %s\n", element
->string
);
1500 /* Help display function for all node. */
1503 "list [permutations]",
1504 "Print command list\n"
1505 "Print all possible command permutations\n")
1507 return cmd_list_cmds(vty
, argc
== 2);
1510 DEFUN (show_commandtree
,
1511 show_commandtree_cmd
,
1512 "show commandtree [permutations]",
1514 "Show command tree\n"
1515 "Permutations that we are interested in\n")
1517 return cmd_list_cmds(vty
, argc
== 3);
1520 static void vty_write_config(struct vty
*vty
)
1523 struct cmd_node
*node
;
1525 if (vty
->type
== VTY_TERM
) {
1526 vty_out(vty
, "\nCurrent configuration:\n");
1527 vty_out(vty
, "!\n");
1530 vty_out(vty
, "frr version %s\n", FRR_VER_SHORT
);
1531 vty_out(vty
, "frr defaults %s\n", DFLT_NAME
);
1532 vty_out(vty
, "!\n");
1534 for (i
= 0; i
< vector_active(cmdvec
); i
++)
1535 if ((node
= vector_slot(cmdvec
, i
)) && node
->func
1536 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
)) {
1537 if ((*node
->func
)(vty
))
1538 vty_out(vty
, "!\n");
1541 if (vty
->type
== VTY_TERM
) {
1542 vty_out(vty
, "end\n");
1546 /* Write current configuration into file. */
1548 DEFUN (config_write
,
1550 "write [<file|memory|terminal>]",
1551 "Write running configuration to memory, network, or terminal\n"
1552 "Write to configuration file\n"
1553 "Write configuration currently in memory\n"
1554 "Write configuration to terminal\n")
1558 char *config_file
, *slash
;
1559 char *config_file_tmp
= NULL
;
1560 char *config_file_sav
= NULL
;
1561 int ret
= CMD_WARNING
;
1562 struct vty
*file_vty
;
1563 struct stat conf_stat
;
1565 // if command was 'write terminal' or 'show running-config'
1566 if (argc
== 2 && (strmatch(argv
[idx_type
]->text
, "terminal")
1567 || strmatch(argv
[0]->text
, "show"))) {
1568 vty_write_config(vty
);
1575 /* Check and see if we are operating under vtysh configuration */
1576 if (host
.config
== NULL
) {
1578 "Can't save to configuration file, using vtysh.\n");
1583 config_file
= host
.config
;
1586 #define O_DIRECTORY 0
1588 slash
= strrchr(config_file
, '/');
1590 char *config_dir
= XSTRDUP(MTYPE_TMP
, config_file
);
1591 config_dir
[slash
- config_file
] = '\0';
1592 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1593 XFREE(MTYPE_TMP
, config_dir
);
1595 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1596 /* if dirfd is invalid, directory sync fails, but we're still OK */
1598 config_file_sav
= XMALLOC(
1599 MTYPE_TMP
, strlen(config_file
) + strlen(CONF_BACKUP_EXT
) + 1);
1600 strcpy(config_file_sav
, config_file
);
1601 strcat(config_file_sav
, CONF_BACKUP_EXT
);
1604 config_file_tmp
= XMALLOC(MTYPE_TMP
, strlen(config_file
) + 8);
1605 sprintf(config_file_tmp
, "%s.XXXXXX", config_file
);
1607 /* Open file to configuration write. */
1608 fd
= mkstemp(config_file_tmp
);
1610 vty_out(vty
, "Can't open configuration file %s.\n",
1614 if (fchmod(fd
, CONFIGFILE_MASK
) != 0) {
1615 vty_out(vty
, "Can't chmod configuration file %s: %s (%d).\n",
1616 config_file_tmp
, safe_strerror(errno
), errno
);
1620 /* Make vty for configuration file. */
1621 file_vty
= vty_new();
1623 file_vty
->type
= VTY_FILE
;
1625 /* Config file header print. */
1626 vty_out(file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1627 vty_time_print(file_vty
, 1);
1628 vty_out(file_vty
, "!\n");
1629 vty_write_config(file_vty
);
1630 vty_close(file_vty
);
1632 if (stat(config_file
, &conf_stat
) >= 0) {
1633 if (unlink(config_file_sav
) != 0)
1634 if (errno
!= ENOENT
) {
1636 "Can't unlink backup configuration file %s.\n",
1640 if (link(config_file
, config_file_sav
) != 0) {
1642 "Can't backup old configuration file %s.\n",
1649 if (rename(config_file_tmp
, config_file
) != 0) {
1650 vty_out(vty
, "Can't save configuration file %s.\n",
1657 vty_out(vty
, "Configuration saved to %s\n", config_file
);
1661 if (ret
!= CMD_SUCCESS
)
1662 unlink(config_file_tmp
);
1665 XFREE(MTYPE_TMP
, config_file_tmp
);
1666 XFREE(MTYPE_TMP
, config_file_sav
);
1670 /* ALIAS_FIXME for 'write <terminal|memory>' */
1671 DEFUN (show_running_config
,
1672 show_running_config_cmd
,
1673 "show running-config",
1675 "running configuration (same as write terminal/memory)\n")
1677 return config_write(self
, vty
, argc
, argv
);
1680 /* ALIAS_FIXME for 'write file' */
1681 DEFUN (copy_runningconf_startupconf
,
1682 copy_runningconf_startupconf_cmd
,
1683 "copy running-config startup-config",
1684 "Copy configuration\n"
1685 "Copy running config to... \n"
1686 "Copy running config to startup config (same as write file)\n")
1689 vty_write_config(vty
);
1694 /* Write startup configuration into the terminal. */
1695 DEFUN (show_startup_config
,
1696 show_startup_config_cmd
,
1697 "show startup-config",
1699 "Contents of startup configuration\n")
1706 if (host
.config
== NULL
)
1709 confp
= fopen(host
.config
, "r");
1710 if (confp
== NULL
) {
1711 vty_out(vty
, "Can't open configuration file [%s] due to '%s'\n",
1712 host
.config
, safe_strerror(errno
));
1716 while (fgets(buf
, BUFSIZ
, confp
)) {
1719 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1723 vty_out(vty
, "%s\n", buf
);
1731 int cmd_hostname_set(const char *hostname
)
1733 XFREE(MTYPE_HOST
, host
.name
);
1734 host
.name
= hostname
? XSTRDUP(MTYPE_HOST
, hostname
) : NULL
;
1738 /* Hostname configuration */
1739 DEFUN (config_hostname
,
1742 "Set system's network name\n"
1743 "This system's network name\n")
1745 struct cmd_token
*word
= argv
[1];
1747 if (!isalpha((int)word
->arg
[0])) {
1748 vty_out(vty
, "Please specify string starting with alphabet\n");
1749 return CMD_WARNING_CONFIG_FAILED
;
1752 return cmd_hostname_set(word
->arg
);
1755 DEFUN (config_no_hostname
,
1757 "no hostname [HOSTNAME]",
1759 "Reset system's network name\n"
1760 "Host name of this router\n")
1762 return cmd_hostname_set(NULL
);
1765 /* VTY interface password set. */
1766 DEFUN (config_password
,
1768 "password [(8-8)] WORD",
1769 "Assign the terminal connection password\n"
1770 "Specifies a HIDDEN password will follow\n"
1771 "The password string\n")
1775 if (argc
== 3) // '8' was specified
1778 XFREE(MTYPE_HOST
, host
.password
);
1779 host
.password
= NULL
;
1780 if (host
.password_encrypt
)
1781 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1782 host
.password_encrypt
=
1783 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1787 if (!isalnum(argv
[idx_8
]->arg
[0])) {
1789 "Please specify string starting with alphanumeric\n");
1790 return CMD_WARNING_CONFIG_FAILED
;
1794 XFREE(MTYPE_HOST
, host
.password
);
1795 host
.password
= NULL
;
1798 if (host
.password_encrypt
)
1799 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1800 host
.password_encrypt
=
1801 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1803 host
.password
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1808 /* VTY enable password set. */
1809 DEFUN (config_enable_password
,
1810 enable_password_cmd
,
1811 "enable password [(8-8)] WORD",
1812 "Modify enable password parameters\n"
1813 "Assign the privileged level password\n"
1814 "Specifies a HIDDEN password will follow\n"
1815 "The HIDDEN 'enable' password string\n")
1820 /* Crypt type is specified. */
1822 if (argv
[idx_8
]->arg
[0] == '8') {
1824 XFREE(MTYPE_HOST
, host
.enable
);
1827 if (host
.enable_encrypt
)
1828 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1829 host
.enable_encrypt
=
1830 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1834 vty_out(vty
, "Unknown encryption type.\n");
1835 return CMD_WARNING_CONFIG_FAILED
;
1839 if (!isalnum(argv
[idx_8
]->arg
[0])) {
1841 "Please specify string starting with alphanumeric\n");
1842 return CMD_WARNING_CONFIG_FAILED
;
1846 XFREE(MTYPE_HOST
, host
.enable
);
1849 /* Plain password input. */
1851 if (host
.enable_encrypt
)
1852 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1853 host
.enable_encrypt
=
1854 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1856 host
.enable
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1861 /* VTY enable password delete. */
1862 DEFUN (no_config_enable_password
,
1863 no_enable_password_cmd
,
1864 "no enable password",
1866 "Modify enable password parameters\n"
1867 "Assign the privileged level password\n")
1870 XFREE(MTYPE_HOST
, host
.enable
);
1873 if (host
.enable_encrypt
)
1874 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1875 host
.enable_encrypt
= NULL
;
1880 DEFUN (service_password_encrypt
,
1881 service_password_encrypt_cmd
,
1882 "service password-encryption",
1883 "Set up miscellaneous service\n"
1884 "Enable encrypted passwords\n")
1891 if (host
.password
) {
1892 if (host
.password_encrypt
)
1893 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1894 host
.password_encrypt
=
1895 XSTRDUP(MTYPE_HOST
, zencrypt(host
.password
));
1898 if (host
.enable_encrypt
)
1899 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1900 host
.enable_encrypt
=
1901 XSTRDUP(MTYPE_HOST
, zencrypt(host
.enable
));
1907 DEFUN (no_service_password_encrypt
,
1908 no_service_password_encrypt_cmd
,
1909 "no service password-encryption",
1911 "Set up miscellaneous service\n"
1912 "Enable encrypted passwords\n")
1919 if (host
.password_encrypt
)
1920 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1921 host
.password_encrypt
= NULL
;
1923 if (host
.enable_encrypt
)
1924 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1925 host
.enable_encrypt
= NULL
;
1930 DEFUN (config_terminal_length
,
1931 config_terminal_length_cmd
,
1932 "terminal length (0-512)",
1933 "Set terminal line parameters\n"
1934 "Set number of lines on a screen\n"
1935 "Number of lines on screen (0 for no pausing)\n")
1939 vty
->lines
= atoi(argv
[idx_number
]->arg
);
1944 DEFUN (config_terminal_no_length
,
1945 config_terminal_no_length_cmd
,
1946 "terminal no length",
1947 "Set terminal line parameters\n"
1949 "Set number of lines on a screen\n")
1955 DEFUN (service_terminal_length
,
1956 service_terminal_length_cmd
,
1957 "service terminal-length (0-512)",
1958 "Set up miscellaneous service\n"
1959 "System wide terminal length configuration\n"
1960 "Number of lines of VTY (0 means no line control)\n")
1964 host
.lines
= atoi(argv
[idx_number
]->arg
);
1969 DEFUN (no_service_terminal_length
,
1970 no_service_terminal_length_cmd
,
1971 "no service terminal-length [(0-512)]",
1973 "Set up miscellaneous service\n"
1974 "System wide terminal length configuration\n"
1975 "Number of lines of VTY (0 means no line control)\n")
1981 DEFUN_HIDDEN (do_echo
,
1984 "Echo a message back to the vty\n"
1985 "The message to echo\n")
1989 vty_out(vty
, "%s\n",
1990 ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
1992 XFREE(MTYPE_TMP
, message
);
1996 DEFUN (config_logmsg
,
1998 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
1999 "Send a message to enabled logging destinations\n"
2001 "The message to send\n")
2003 int idx_log_level
= 1;
2004 int idx_message
= 2;
2008 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2009 return CMD_ERR_NO_MATCH
;
2012 ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2014 XFREE(MTYPE_TMP
, message
);
2019 DEFUN (show_logging
,
2023 "Show current logging configuration\n")
2025 struct zlog
*zl
= zlog_default
;
2027 vty_out(vty
, "Syslog logging: ");
2028 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2029 vty_out(vty
, "disabled");
2031 vty_out(vty
, "level %s, facility %s, ident %s",
2032 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2033 facility_name(zl
->facility
), zl
->ident
);
2036 vty_out(vty
, "Stdout logging: ");
2037 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2038 vty_out(vty
, "disabled");
2040 vty_out(vty
, "level %s",
2041 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2044 vty_out(vty
, "Monitor logging: ");
2045 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2046 vty_out(vty
, "disabled");
2048 vty_out(vty
, "level %s",
2049 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2052 vty_out(vty
, "File logging: ");
2053 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) || !zl
->fp
)
2054 vty_out(vty
, "disabled");
2056 vty_out(vty
, "level %s, filename %s",
2057 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2061 vty_out(vty
, "Protocol name: %s\n", zl
->protoname
);
2062 vty_out(vty
, "Record priority: %s\n",
2063 (zl
->record_priority
? "enabled" : "disabled"));
2064 vty_out(vty
, "Timestamp precision: %d\n", zl
->timestamp_precision
);
2069 DEFUN (config_log_stdout
,
2070 config_log_stdout_cmd
,
2071 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2073 "Set stdout logging level\n"
2076 int idx_log_level
= 2;
2078 if (argc
== idx_log_level
) {
2079 zlog_set_level(ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2084 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2085 return CMD_ERR_NO_MATCH
;
2086 zlog_set_level(ZLOG_DEST_STDOUT
, level
);
2090 DEFUN (no_config_log_stdout
,
2091 no_config_log_stdout_cmd
,
2092 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2095 "Cancel logging to stdout\n"
2098 zlog_set_level(ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2102 DEFUN (config_log_monitor
,
2103 config_log_monitor_cmd
,
2104 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2106 "Set terminal line (monitor) logging level\n"
2109 int idx_log_level
= 2;
2111 if (argc
== idx_log_level
) {
2112 zlog_set_level(ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2117 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2118 return CMD_ERR_NO_MATCH
;
2119 zlog_set_level(ZLOG_DEST_MONITOR
, level
);
2123 DEFUN (no_config_log_monitor
,
2124 no_config_log_monitor_cmd
,
2125 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2128 "Disable terminal line (monitor) logging\n"
2131 zlog_set_level(ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2135 static int set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2139 const char *fullpath
;
2141 /* Path detection. */
2142 if (!IS_DIRECTORY_SEP(*fname
)) {
2143 char cwd
[MAXPATHLEN
+ 1];
2144 cwd
[MAXPATHLEN
] = '\0';
2146 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
2147 zlog_err("config_log_file: Unable to alloc mem!");
2148 return CMD_WARNING_CONFIG_FAILED
;
2151 if ((p
= XMALLOC(MTYPE_TMP
, strlen(cwd
) + strlen(fname
) + 2))
2153 zlog_err("config_log_file: Unable to alloc mem!");
2154 return CMD_WARNING_CONFIG_FAILED
;
2156 sprintf(p
, "%s/%s", cwd
, fname
);
2161 ret
= zlog_set_file(fullpath
, loglevel
);
2164 XFREE(MTYPE_TMP
, p
);
2167 vty_out(vty
, "can't open logfile %s\n", fname
);
2168 return CMD_WARNING_CONFIG_FAILED
;
2172 XFREE(MTYPE_HOST
, host
.logfile
);
2174 host
.logfile
= XSTRDUP(MTYPE_HOST
, fname
);
2176 #if defined(HAVE_CUMULUS)
2177 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2178 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2183 DEFUN (config_log_file
,
2184 config_log_file_cmd
,
2185 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2188 "Logging filename\n"
2191 int idx_filename
= 2;
2192 int idx_log_levels
= 3;
2195 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2197 return CMD_ERR_NO_MATCH
;
2198 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2200 return set_log_file(vty
, argv
[idx_filename
]->arg
,
2201 zlog_default
->default_lvl
);
2204 DEFUN (no_config_log_file
,
2205 no_config_log_file_cmd
,
2206 "no log file [FILENAME [LEVEL]]",
2209 "Cancel logging to file\n"
2210 "Logging file name\n"
2216 XFREE(MTYPE_HOST
, host
.logfile
);
2218 host
.logfile
= NULL
;
2223 DEFUN (config_log_syslog
,
2224 config_log_syslog_cmd
,
2225 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2227 "Set syslog logging level\n"
2230 int idx_log_levels
= 2;
2233 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2235 return CMD_ERR_NO_MATCH
;
2236 zlog_set_level(ZLOG_DEST_SYSLOG
, level
);
2239 zlog_set_level(ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2244 DEFUN (no_config_log_syslog
,
2245 no_config_log_syslog_cmd
,
2246 "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>]",
2249 "Cancel logging to syslog\n"
2253 zlog_set_level(ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2257 DEFUN (config_log_facility
,
2258 config_log_facility_cmd
,
2259 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2261 "Facility parameter for syslog messages\n"
2265 int facility
= facility_match(argv
[idx_target
]->arg
);
2267 zlog_default
->facility
= facility
;
2271 DEFUN (no_config_log_facility
,
2272 no_config_log_facility_cmd
,
2273 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2276 "Reset syslog facility to default (daemon)\n"
2279 zlog_default
->facility
= LOG_DAEMON
;
2284 config_log_trap
, config_log_trap_cmd
,
2285 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2287 "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC
)
2292 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2293 return CMD_ERR_NO_MATCH
;
2295 zlog_default
->default_lvl
= new_level
;
2296 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2297 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2298 zlog_default
->maxlvl
[i
] = new_level
;
2303 no_config_log_trap
, no_config_log_trap_cmd
,
2304 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2307 "Permit all logging information\n" LOG_LEVEL_DESC
)
2309 zlog_default
->default_lvl
= LOG_DEBUG
;
2313 DEFUN (config_log_record_priority
,
2314 config_log_record_priority_cmd
,
2315 "log record-priority",
2317 "Log the priority of the message within the message\n")
2319 zlog_default
->record_priority
= 1;
2323 DEFUN (no_config_log_record_priority
,
2324 no_config_log_record_priority_cmd
,
2325 "no log record-priority",
2328 "Do not log the priority of the message within the message\n")
2330 zlog_default
->record_priority
= 0;
2334 DEFUN (config_log_timestamp_precision
,
2335 config_log_timestamp_precision_cmd
,
2336 "log timestamp precision (0-6)",
2338 "Timestamp configuration\n"
2339 "Set the timestamp precision\n"
2340 "Number of subsecond digits\n")
2343 zlog_default
->timestamp_precision
=
2344 strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2348 DEFUN (no_config_log_timestamp_precision
,
2349 no_config_log_timestamp_precision_cmd
,
2350 "no log timestamp precision",
2353 "Timestamp configuration\n"
2354 "Reset the timestamp precision to the default value of 0\n")
2356 zlog_default
->timestamp_precision
= 0;
2360 int cmd_banner_motd_file(const char *file
)
2362 int success
= CMD_SUCCESS
;
2367 rpath
= realpath(file
, p
);
2369 return CMD_ERR_NO_FILE
;
2370 in
= strstr(rpath
, SYSCONFDIR
);
2373 XFREE(MTYPE_HOST
, host
.motdfile
);
2374 host
.motdfile
= XSTRDUP(MTYPE_HOST
, file
);
2376 success
= CMD_WARNING_CONFIG_FAILED
;
2381 DEFUN (banner_motd_file
,
2382 banner_motd_file_cmd
,
2383 "banner motd file FILE",
2386 "Banner from a file\n"
2390 const char *filename
= argv
[idx_file
]->arg
;
2391 int cmd
= cmd_banner_motd_file(filename
);
2393 if (cmd
== CMD_ERR_NO_FILE
)
2394 vty_out(vty
, "%s does not exist", filename
);
2395 else if (cmd
== CMD_WARNING_CONFIG_FAILED
)
2396 vty_out(vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2401 DEFUN (banner_motd_default
,
2402 banner_motd_default_cmd
,
2403 "banner motd default",
2404 "Set banner string\n"
2405 "Strings for motd\n"
2408 host
.motd
= default_motd
;
2412 DEFUN (no_banner_motd
,
2416 "Set banner string\n"
2417 "Strings for motd\n")
2421 XFREE(MTYPE_HOST
, host
.motdfile
);
2422 host
.motdfile
= NULL
;
2429 "Find CLI command containing text\n"
2430 "Text to search for\n")
2432 char *text
= argv_concat(argv
, argc
, 1);
2433 const struct cmd_node
*node
;
2434 const struct cmd_element
*cli
;
2437 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++) {
2438 node
= vector_slot(cmdvec
, i
);
2441 clis
= node
->cmd_vector
;
2442 for (unsigned int j
= 0; j
< vector_active(clis
); j
++) {
2443 cli
= vector_slot(clis
, j
);
2444 if (strcasestr(cli
->string
, text
))
2445 vty_out(vty
, " (%s) %s\n",
2446 node_names
[node
->node
], cli
->string
);
2450 XFREE(MTYPE_TMP
, text
);
2455 /* Set config filename. Called from vty.c */
2456 void host_config_set(const char *filename
)
2459 XFREE(MTYPE_HOST
, host
.config
);
2460 host
.config
= XSTRDUP(MTYPE_HOST
, filename
);
2463 const char *host_config_get(void)
2468 void install_default(enum node_type node
)
2470 install_element(node
, &config_exit_cmd
);
2471 install_element(node
, &config_quit_cmd
);
2472 install_element(node
, &config_end_cmd
);
2473 install_element(node
, &config_help_cmd
);
2474 install_element(node
, &config_list_cmd
);
2475 install_element(node
, &find_cmd
);
2477 install_element(node
, &config_write_cmd
);
2478 install_element(node
, &show_running_config_cmd
);
2480 install_element(node
, &autocomplete_cmd
);
2483 /* Initialize command interface. Install basic nodes and commands.
2485 * terminal = 0 -- vtysh / no logging, no config control
2486 * terminal = 1 -- normal daemon
2487 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2488 void cmd_init(int terminal
)
2490 if (array_size(node_names
) != NODE_TYPE_MAX
)
2491 assert(!"Update the CLI node description array!");
2495 varhandlers
= list_new();
2497 /* Allocate initial top vector of commands. */
2498 cmdvec
= vector_init(VECTOR_MIN_SIZE
);
2500 /* Default host value settings. */
2502 host
.password
= NULL
;
2504 host
.logfile
= NULL
;
2506 host
.noconfig
= (terminal
< 0);
2508 host
.motd
= default_motd
;
2509 host
.motdfile
= NULL
;
2511 /* Install top nodes. */
2512 install_node(&view_node
, NULL
);
2513 install_node(&enable_node
, NULL
);
2514 install_node(&auth_node
, NULL
);
2515 install_node(&auth_enable_node
, NULL
);
2516 install_node(&config_node
, config_write_host
);
2518 /* Each node's basic commands. */
2519 install_element(VIEW_NODE
, &show_version_cmd
);
2520 install_element(ENABLE_NODE
, &show_startup_config_cmd
);
2523 install_element(VIEW_NODE
, &config_list_cmd
);
2524 install_element(VIEW_NODE
, &config_exit_cmd
);
2525 install_element(VIEW_NODE
, &config_quit_cmd
);
2526 install_element(VIEW_NODE
, &config_help_cmd
);
2527 install_element(VIEW_NODE
, &config_enable_cmd
);
2528 install_element(VIEW_NODE
, &config_terminal_length_cmd
);
2529 install_element(VIEW_NODE
, &config_terminal_no_length_cmd
);
2530 install_element(VIEW_NODE
, &show_logging_cmd
);
2531 install_element(VIEW_NODE
, &show_commandtree_cmd
);
2532 install_element(VIEW_NODE
, &echo_cmd
);
2533 install_element(VIEW_NODE
, &autocomplete_cmd
);
2534 install_element(VIEW_NODE
, &find_cmd
);
2536 install_element(ENABLE_NODE
, &config_end_cmd
);
2537 install_element(ENABLE_NODE
, &config_disable_cmd
);
2538 install_element(ENABLE_NODE
, &config_terminal_cmd
);
2539 install_element(ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2540 install_element(ENABLE_NODE
, &config_write_cmd
);
2541 install_element(ENABLE_NODE
, &show_running_config_cmd
);
2542 install_element(ENABLE_NODE
, &config_logmsg_cmd
);
2544 install_default(CONFIG_NODE
);
2547 workqueue_cmd_init();
2551 install_element(CONFIG_NODE
, &hostname_cmd
);
2552 install_element(CONFIG_NODE
, &no_hostname_cmd
);
2553 install_element(CONFIG_NODE
, &frr_version_defaults_cmd
);
2556 install_element(CONFIG_NODE
, &password_cmd
);
2557 install_element(CONFIG_NODE
, &enable_password_cmd
);
2558 install_element(CONFIG_NODE
, &no_enable_password_cmd
);
2560 install_element(CONFIG_NODE
, &config_log_stdout_cmd
);
2561 install_element(CONFIG_NODE
, &no_config_log_stdout_cmd
);
2562 install_element(CONFIG_NODE
, &config_log_monitor_cmd
);
2563 install_element(CONFIG_NODE
, &no_config_log_monitor_cmd
);
2564 install_element(CONFIG_NODE
, &config_log_file_cmd
);
2565 install_element(CONFIG_NODE
, &no_config_log_file_cmd
);
2566 install_element(CONFIG_NODE
, &config_log_syslog_cmd
);
2567 install_element(CONFIG_NODE
, &no_config_log_syslog_cmd
);
2568 install_element(CONFIG_NODE
, &config_log_facility_cmd
);
2569 install_element(CONFIG_NODE
, &no_config_log_facility_cmd
);
2570 install_element(CONFIG_NODE
, &config_log_trap_cmd
);
2571 install_element(CONFIG_NODE
, &no_config_log_trap_cmd
);
2572 install_element(CONFIG_NODE
, &config_log_record_priority_cmd
);
2573 install_element(CONFIG_NODE
,
2574 &no_config_log_record_priority_cmd
);
2575 install_element(CONFIG_NODE
,
2576 &config_log_timestamp_precision_cmd
);
2577 install_element(CONFIG_NODE
,
2578 &no_config_log_timestamp_precision_cmd
);
2579 install_element(CONFIG_NODE
, &service_password_encrypt_cmd
);
2580 install_element(CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2581 install_element(CONFIG_NODE
, &banner_motd_default_cmd
);
2582 install_element(CONFIG_NODE
, &banner_motd_file_cmd
);
2583 install_element(CONFIG_NODE
, &no_banner_motd_cmd
);
2584 install_element(CONFIG_NODE
, &service_terminal_length_cmd
);
2585 install_element(CONFIG_NODE
, &no_service_terminal_length_cmd
);
2587 vrf_install_commands();
2591 grammar_sandbox_init();
2595 void cmd_terminate()
2597 struct cmd_node
*cmd_node
;
2600 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++)
2601 if ((cmd_node
= vector_slot(cmdvec
, i
)) != NULL
) {
2602 // deleting the graph delets the cmd_element as
2604 graph_delete_graph(cmd_node
->cmdgraph
);
2605 vector_free(cmd_node
->cmd_vector
);
2606 hash_clean(cmd_node
->cmd_hash
, NULL
);
2607 hash_free(cmd_node
->cmd_hash
);
2608 cmd_node
->cmd_hash
= NULL
;
2611 vector_free(cmdvec
);
2616 XFREE(MTYPE_HOST
, host
.name
);
2618 XFREE(MTYPE_HOST
, host
.password
);
2619 if (host
.password_encrypt
)
2620 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2622 XFREE(MTYPE_HOST
, host
.enable
);
2623 if (host
.enable_encrypt
)
2624 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2626 XFREE(MTYPE_HOST
, host
.logfile
);
2628 XFREE(MTYPE_HOST
, host
.motdfile
);
2630 XFREE(MTYPE_HOST
, host
.config
);
2632 list_delete(varhandlers
);