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 "MAC access list", // ACCESS_MAC_NODE,
105 "ipv6 prefix list", // PREFIX_IPV6_NODE,
106 "as list", // AS_LIST_NODE,
107 "community list", // COMMUNITY_LIST_NODE,
108 "routemap", // RMAP_NODE,
109 "smux", // SMUX_NODE,
110 "dump", // DUMP_NODE,
111 "forwarding", // FORWARDING_NODE,
112 "protocol", // PROTOCOL_NODE,
113 "mpls", // MPLS_NODE,
116 "link-params", // LINK_PARAMS_NODE,
117 "bgp evpn vni", // BGP_EVPN_VNI_NODE,
120 /* Command vector which includes some level of command lists. Normally
121 each daemon maintains each own cmdvec. */
122 vector cmdvec
= NULL
;
124 /* Host information structure. */
127 /* Standard command node structures. */
128 static struct cmd_node auth_node
= {
129 AUTH_NODE
, "Password: ",
132 static struct cmd_node view_node
= {
136 static struct cmd_node auth_enable_node
= {
137 AUTH_ENABLE_NODE
, "Password: ",
140 static struct cmd_node enable_node
= {
144 static struct cmd_node config_node
= {CONFIG_NODE
, "%s(config)# ", 1};
146 /* Default motd string. */
147 static const char *default_motd
= FRR_DEFAULT_MOTD
;
149 static const struct facility_map
{
153 } syslog_facilities
[] = {
154 {LOG_KERN
, "kern", 1},
155 {LOG_USER
, "user", 2},
156 {LOG_MAIL
, "mail", 1},
157 {LOG_DAEMON
, "daemon", 1},
158 {LOG_AUTH
, "auth", 1},
159 {LOG_SYSLOG
, "syslog", 1},
161 {LOG_NEWS
, "news", 1},
162 {LOG_UUCP
, "uucp", 2},
163 {LOG_CRON
, "cron", 1},
167 {LOG_LOCAL0
, "local0", 6},
168 {LOG_LOCAL1
, "local1", 6},
169 {LOG_LOCAL2
, "local2", 6},
170 {LOG_LOCAL3
, "local3", 6},
171 {LOG_LOCAL4
, "local4", 6},
172 {LOG_LOCAL5
, "local5", 6},
173 {LOG_LOCAL6
, "local6", 6},
174 {LOG_LOCAL7
, "local7", 6},
178 static const char *facility_name(int facility
)
180 const struct facility_map
*fm
;
182 for (fm
= syslog_facilities
; fm
->name
; fm
++)
183 if (fm
->facility
== facility
)
188 static int facility_match(const char *str
)
190 const struct facility_map
*fm
;
192 for (fm
= syslog_facilities
; fm
->name
; fm
++)
193 if (!strncmp(str
, fm
->name
, fm
->match
))
198 static int level_match(const char *s
)
202 for (level
= 0; zlog_priority
[level
] != NULL
; level
++)
203 if (!strncmp(s
, zlog_priority
[level
], 2))
205 return ZLOG_DISABLED
;
208 /* This is called from main when a daemon is invoked with -v or --version. */
209 void print_version(const char *progname
)
211 printf("%s version %s\n", progname
, FRR_VERSION
);
212 printf("%s\n", FRR_COPYRIGHT
);
213 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
217 /* Utility function to concatenate argv argument into a single string
218 with inserting ' ' character between each argument. */
219 char *argv_concat(struct cmd_token
**argv
, int argc
, int shift
)
227 for (i
= shift
; i
< argc
; i
++)
228 len
+= strlen(argv
[i
]->arg
) + 1;
231 p
= str
= XMALLOC(MTYPE_TMP
, len
);
232 for (i
= shift
; i
< argc
; i
++) {
234 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
243 * Convenience function for accessing argv data.
247 * @param text definition snippet of the desired token
248 * @param index the starting index, and where to store the
249 * index of the found token if it exists
250 * @return 1 if found, 0 otherwise
252 int argv_find(struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
255 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
256 if ((found
= strmatch(text
, argv
[i
]->text
)))
261 static unsigned int cmd_hash_key(void *p
)
266 static int cmd_hash_cmp(const void *a
, const void *b
)
271 /* Install top node of command vector. */
272 void install_node(struct cmd_node
*node
, int (*func
)(struct vty
*))
274 vector_set_index(cmdvec
, node
->node
, node
);
276 node
->cmdgraph
= graph_new();
277 node
->cmd_vector
= vector_init(VECTOR_MIN_SIZE
);
279 struct cmd_token
*token
=
280 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
281 graph_new_node(node
->cmdgraph
, token
,
282 (void (*)(void *)) & cmd_token_del
);
283 node
->cmd_hash
= hash_create(cmd_hash_key
, cmd_hash_cmp
, NULL
);
287 * Tokenizes a string, storing tokens in a vector.
288 * Whitespace is ignored.
290 * Delimiter string = " \n\r\t".
292 * @param string to tokenize
293 * @return tokenized string
295 vector
cmd_make_strvec(const char *string
)
300 char *copy
, *copystart
;
301 copystart
= copy
= XSTRDUP(MTYPE_TMP
, string
);
303 // skip leading whitespace
304 while (isspace((int)*copy
) && *copy
!= '\0')
307 // if the entire string was whitespace or a comment, return
308 if (*copy
== '\0' || *copy
== '!' || *copy
== '#') {
309 XFREE(MTYPE_TMP
, copystart
);
313 vector strvec
= vector_init(VECTOR_MIN_SIZE
);
314 const char *delim
= " \n\r\t", *tok
= NULL
;
316 tok
= strsep(©
, delim
);
318 vector_set(strvec
, XSTRDUP(MTYPE_STRVEC
, tok
));
321 XFREE(MTYPE_TMP
, copystart
);
325 /* Free allocated string vector. */
326 void cmd_free_strvec(vector v
)
334 for (i
= 0; i
< vector_active(v
); i
++)
335 if ((cp
= vector_slot(v
, i
)) != NULL
)
336 XFREE(MTYPE_STRVEC
, cp
);
341 /* Return prompt character of specified node. */
342 const char *cmd_prompt(enum node_type node
)
344 struct cmd_node
*cnode
;
346 cnode
= vector_slot(cmdvec
, node
);
347 return cnode
->prompt
;
350 /* Install a command into a node. */
351 void install_element(enum node_type ntype
, struct cmd_element
*cmd
)
353 struct cmd_node
*cnode
;
355 /* cmd_init hasn't been called */
357 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
362 cnode
= vector_slot(cmdvec
, ntype
);
366 "Command node %d doesn't exist, please check it\n",
369 "Have you called install_node before this install_element?\n");
373 if (hash_lookup(cnode
->cmd_hash
, cmd
) != NULL
) {
375 "Multiple command installs to node %d of command:\n%s\n",
380 assert(hash_get(cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
382 struct graph
*graph
= graph_new();
383 struct cmd_token
*token
=
384 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
385 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
387 cmd_graph_parse(graph
, cmd
);
388 cmd_graph_names(graph
);
389 cmd_graph_merge(cnode
->cmdgraph
, graph
, +1);
390 graph_delete_graph(graph
);
392 vector_set(cnode
->cmd_vector
, cmd
);
394 if (ntype
== VIEW_NODE
)
395 install_element(ENABLE_NODE
, cmd
);
398 void uninstall_element(enum node_type ntype
, struct cmd_element
*cmd
)
400 struct cmd_node
*cnode
;
402 /* cmd_init hasn't been called */
404 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
409 cnode
= vector_slot(cmdvec
, ntype
);
413 "Command node %d doesn't exist, please check it\n",
416 "Have you called install_node before this install_element?\n");
420 if (hash_release(cnode
->cmd_hash
, cmd
) == NULL
) {
422 "Trying to uninstall non-installed command (node %d):\n%s\n",
427 vector_unset_value(cnode
->cmd_vector
, cmd
);
429 struct graph
*graph
= graph_new();
430 struct cmd_token
*token
=
431 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
432 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
434 cmd_graph_parse(graph
, cmd
);
435 cmd_graph_names(graph
);
436 cmd_graph_merge(cnode
->cmdgraph
, graph
, -1);
437 graph_delete_graph(graph
);
439 if (ntype
== VIEW_NODE
)
440 uninstall_element(ENABLE_NODE
, cmd
);
444 static const unsigned char itoa64
[] =
445 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
447 static void to64(char *s
, long v
, int n
)
450 *s
++ = itoa64
[v
& 0x3f];
455 static char *zencrypt(const char *passwd
)
459 char *crypt(const char *, const char *);
461 gettimeofday(&tv
, 0);
463 to64(&salt
[0], random(), 3);
464 to64(&salt
[3], tv
.tv_usec
, 3);
467 return crypt(passwd
, salt
);
470 /* This function write configuration of this host. */
471 static int config_write_host(struct vty
*vty
)
474 vty_out(vty
, "hostname %s\n", host
.name
);
477 if (host
.password_encrypt
)
478 vty_out(vty
, "password 8 %s\n", host
.password_encrypt
);
479 if (host
.enable_encrypt
)
480 vty_out(vty
, "enable password 8 %s\n",
481 host
.enable_encrypt
);
484 vty_out(vty
, "password %s\n", host
.password
);
486 vty_out(vty
, "enable password %s\n", host
.enable
);
489 if (zlog_default
->default_lvl
!= LOG_DEBUG
) {
490 vty_out(vty
, "! N.B. The 'log trap' command is deprecated.\n");
491 vty_out(vty
, "log trap %s\n",
492 zlog_priority
[zlog_default
->default_lvl
]);
496 && (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
)) {
497 vty_out(vty
, "log file %s", host
.logfile
);
498 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
]
499 != zlog_default
->default_lvl
)
502 [zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
506 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
) {
507 vty_out(vty
, "log stdout");
508 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]
509 != zlog_default
->default_lvl
)
511 zlog_priority
[zlog_default
->maxlvl
512 [ZLOG_DEST_STDOUT
]]);
516 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
517 vty_out(vty
, "no log monitor\n");
518 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]
519 != zlog_default
->default_lvl
)
520 vty_out(vty
, "log monitor %s\n",
521 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]]);
523 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
) {
524 vty_out(vty
, "log syslog");
525 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]
526 != zlog_default
->default_lvl
)
528 zlog_priority
[zlog_default
->maxlvl
529 [ZLOG_DEST_SYSLOG
]]);
533 if (zlog_default
->facility
!= LOG_DAEMON
)
534 vty_out(vty
, "log facility %s\n",
535 facility_name(zlog_default
->facility
));
537 if (zlog_default
->record_priority
== 1)
538 vty_out(vty
, "log record-priority\n");
540 if (zlog_default
->timestamp_precision
> 0)
541 vty_out(vty
, "log timestamp precision %d\n",
542 zlog_default
->timestamp_precision
);
545 vty_out(vty
, "service advanced-vty\n");
548 vty_out(vty
, "service password-encryption\n");
551 vty_out(vty
, "service terminal-length %d\n", host
.lines
);
554 vty_out(vty
, "banner motd file %s\n", host
.motdfile
);
556 vty_out(vty
, "no banner motd\n");
561 /* Utility function for getting command graph. */
562 static struct graph
*cmd_node_graph(vector v
, enum node_type ntype
)
564 struct cmd_node
*cnode
= vector_slot(v
, ntype
);
565 return cnode
->cmdgraph
;
568 static int cmd_try_do_shortcut(enum node_type node
, char *first_word
)
570 if (first_word
!= NULL
&& node
!= AUTH_NODE
&& node
!= VIEW_NODE
571 && node
!= AUTH_ENABLE_NODE
&& 0 == strcmp("do", first_word
))
577 * Compare function for cmd_token.
578 * Used with qsort to sort command completions.
580 static int compare_completions(const void *fst
, const void *snd
)
582 struct cmd_token
*first
= *(struct cmd_token
**)fst
,
583 *secnd
= *(struct cmd_token
**)snd
;
584 return strcmp(first
->text
, secnd
->text
);
588 * Takes a list of completions returned by command_complete,
589 * dedeuplicates them based on both text and description,
590 * sorts them, and returns them as a vector.
592 * @param completions linked list of cmd_token
593 * @return deduplicated and sorted vector with
595 vector
completions_to_vec(struct list
*completions
)
597 vector comps
= vector_init(VECTOR_MIN_SIZE
);
600 struct cmd_token
*token
, *cr
= NULL
;
601 unsigned int i
, exists
;
602 for (ALL_LIST_ELEMENTS_RO(completions
, ln
, token
)) {
603 if (token
->type
== END_TKN
&& (cr
= token
))
606 // linear search for token in completions vector
608 for (i
= 0; i
< vector_active(comps
) && !exists
; i
++) {
609 struct cmd_token
*curr
= vector_slot(comps
, i
);
611 exists
= !strcmp(curr
->text
, token
->text
)
612 && !strcmp(curr
->desc
, token
->desc
);
614 exists
= !strcmp(curr
->text
, token
->text
);
615 #endif /* VTYSH_DEBUG */
619 vector_set(comps
, token
);
623 qsort(comps
->index
, vector_active(comps
), sizeof(void *),
624 &compare_completions
);
626 // make <cr> the first element, if it is present
628 vector_set_index(comps
, vector_active(comps
), NULL
);
629 memmove(comps
->index
+ 1, comps
->index
,
630 (comps
->alloced
- 1) * sizeof(void *));
631 vector_set_index(comps
, 0, cr
);
637 * Generates a vector of cmd_token representing possible completions
638 * on the current input.
640 * @param vline the vectorized input line
641 * @param vty the vty with the node to match on
642 * @param status pointer to matcher status code
643 * @return vector of struct cmd_token * with possible completions
645 static vector
cmd_complete_command_real(vector vline
, struct vty
*vty
,
648 struct list
*completions
;
649 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
651 enum matcher_rv rv
= command_complete(cmdgraph
, vline
, &completions
);
653 if (MATCHER_ERROR(rv
)) {
654 *status
= CMD_ERR_NO_MATCH
;
658 vector comps
= completions_to_vec(completions
);
659 list_delete(completions
);
661 // set status code appropriately
662 switch (vector_active(comps
)) {
664 *status
= CMD_ERR_NO_MATCH
;
667 *status
= CMD_COMPLETE_FULL_MATCH
;
670 *status
= CMD_COMPLETE_LIST_MATCH
;
676 vector
cmd_describe_command(vector vline
, struct vty
*vty
, int *status
)
680 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
681 enum node_type onode
;
682 vector shifted_vline
;
686 vty
->node
= ENABLE_NODE
;
687 /* We can try it on enable node, cos' the vty is authenticated
690 shifted_vline
= vector_init(vector_count(vline
));
692 for (index
= 1; index
< vector_active(vline
); index
++) {
693 vector_set_index(shifted_vline
, index
- 1,
694 vector_lookup(vline
, index
));
697 ret
= cmd_complete_command_real(shifted_vline
, vty
, status
);
699 vector_free(shifted_vline
);
704 return cmd_complete_command_real(vline
, vty
, status
);
707 static struct list
*varhandlers
= NULL
;
709 void cmd_variable_complete(struct cmd_token
*token
, const char *arg
,
713 const struct cmd_variable_handler
*cvh
;
717 tmpcomps
= arg
? vector_init(VECTOR_MIN_SIZE
) : comps
;
719 for (ALL_LIST_ELEMENTS_RO(varhandlers
, ln
, cvh
)) {
720 if (cvh
->tokenname
&& strcmp(cvh
->tokenname
, token
->text
))
722 if (cvh
->varname
&& (!token
->varname
723 || strcmp(cvh
->varname
, token
->varname
)))
725 cvh
->completions(tmpcomps
, token
);
733 for (i
= vector_active(tmpcomps
); i
; i
--) {
734 char *item
= vector_slot(tmpcomps
, i
- 1);
735 if (strlen(item
) >= argsz
&& !strncmp(item
, arg
, argsz
))
736 vector_set(comps
, item
);
738 XFREE(MTYPE_COMPLETION
, item
);
740 vector_free(tmpcomps
);
743 #define AUTOCOMP_INDENT 5
745 char *cmd_variable_comp2str(vector comps
, unsigned short cols
)
748 char *buf
= XCALLOC(MTYPE_TMP
, bsz
);
749 int lc
= AUTOCOMP_INDENT
;
750 size_t cs
= AUTOCOMP_INDENT
;
752 snprintf(buf
, bsz
, "%*s", AUTOCOMP_INDENT
, "");
753 for (size_t j
= 0; j
< vector_active(comps
); j
++) {
754 char *item
= vector_slot(comps
, j
);
755 itemlen
= strlen(item
);
757 if (cs
+ itemlen
+ AUTOCOMP_INDENT
+ 3 >= bsz
)
758 buf
= XREALLOC(MTYPE_TMP
, buf
, (bsz
*= 2));
760 if (lc
+ itemlen
+ 1 >= cols
) {
761 cs
+= snprintf(&buf
[cs
], bsz
- cs
, "\n%*s",
762 AUTOCOMP_INDENT
, "");
763 lc
= AUTOCOMP_INDENT
;
766 size_t written
= snprintf(&buf
[cs
], bsz
- cs
, "%s ", item
);
769 XFREE(MTYPE_COMPLETION
, item
);
770 vector_set_index(comps
, j
, NULL
);
775 void cmd_variable_handler_register(const struct cmd_variable_handler
*cvh
)
780 for (; cvh
->completions
; cvh
++)
781 listnode_add(varhandlers
, (void *)cvh
);
784 DEFUN_HIDDEN (autocomplete
,
786 "autocomplete TYPE TEXT VARNAME",
787 "Autocompletion handler (internal, for vtysh)\n"
790 "cmd_token->varname\n")
792 struct cmd_token tok
;
793 vector comps
= vector_init(32);
796 memset(&tok
, 0, sizeof(tok
));
797 tok
.type
= atoi(argv
[1]->arg
);
798 tok
.text
= argv
[2]->arg
;
799 tok
.varname
= argv
[3]->arg
;
800 if (!strcmp(tok
.varname
, "-"))
803 cmd_variable_complete(&tok
, NULL
, comps
);
805 for (i
= 0; i
< vector_active(comps
); i
++) {
806 char *text
= vector_slot(comps
, i
);
807 vty_out(vty
, "%s\n", text
);
808 XFREE(MTYPE_COMPLETION
, text
);
816 * Generate possible tab-completions for the given input. This function only
817 * returns results that would result in a valid command if used as Readline
818 * completions (as is the case in vtysh). For instance, if the passed vline ends
819 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
821 * @param vline vectorized input line
823 * @param status location to store matcher status code in
824 * @return set of valid strings for use with Readline as tab-completions.
827 char **cmd_complete_command(vector vline
, struct vty
*vty
, int *status
)
830 int original_node
= vty
->node
;
831 vector input_line
= vector_init(vector_count(vline
));
833 // if the first token is 'do' we'll want to execute the command in the
835 int do_shortcut
= cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0));
836 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
838 // construct the input line we'll be matching on
839 unsigned int offset
= (do_shortcut
) ? 1 : 0;
840 for (unsigned index
= 0; index
+ offset
< vector_active(vline
); index
++)
841 vector_set_index(input_line
, index
,
842 vector_lookup(vline
, index
+ offset
));
844 // get token completions -- this is a copying operation
845 vector comps
= NULL
, initial_comps
;
846 initial_comps
= cmd_complete_command_real(input_line
, vty
, status
);
848 if (!MATCHER_ERROR(*status
)) {
849 assert(initial_comps
);
850 // filter out everything that is not suitable for a
852 comps
= vector_init(VECTOR_MIN_SIZE
);
853 for (unsigned int i
= 0; i
< vector_active(initial_comps
);
855 struct cmd_token
*token
= vector_slot(initial_comps
, i
);
856 if (token
->type
== WORD_TKN
)
857 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
,
859 else if (IS_VARYING_TOKEN(token
->type
)) {
860 const char *ref
= vector_lookup(
861 vline
, vector_active(vline
) - 1);
862 cmd_variable_complete(token
, ref
, comps
);
865 vector_free(initial_comps
);
867 // since we filtered results, we need to re-set status code
868 switch (vector_active(comps
)) {
870 *status
= CMD_ERR_NO_MATCH
;
873 *status
= CMD_COMPLETE_FULL_MATCH
;
876 *status
= CMD_COMPLETE_LIST_MATCH
;
879 // copy completions text into an array of char*
880 ret
= XMALLOC(MTYPE_TMP
,
881 (vector_active(comps
) + 1) * sizeof(char *));
883 for (i
= 0; i
< vector_active(comps
); i
++) {
884 ret
[i
] = vector_slot(comps
, i
);
886 // set the last element to NULL, because this array is used in
887 // a Readline completion_generator function which expects NULL
888 // as a sentinel value
892 } else if (initial_comps
)
893 vector_free(initial_comps
);
895 // comps should always be null here
898 // free the adjusted input line
899 vector_free(input_line
);
901 // reset vty->node to its original value
902 vty
->node
= original_node
;
907 /* return parent node */
908 /* MUST eventually converge on CONFIG_NODE */
909 enum node_type
node_parent(enum node_type node
)
913 assert(node
> CONFIG_NODE
);
918 case BGP_VRF_POLICY_NODE
:
919 case BGP_VNC_DEFAULTS_NODE
:
920 case BGP_VNC_NVE_GROUP_NODE
:
921 case BGP_VNC_L2_GROUP_NODE
:
931 case BGP_EVPN_VNI_NODE
:
934 case KEYCHAIN_KEY_NODE
:
937 case LINK_PARAMS_NODE
:
938 ret
= INTERFACE_NODE
;
944 case LDP_IPV4_IFACE_NODE
:
947 case LDP_IPV6_IFACE_NODE
:
950 case LDP_PSEUDOWIRE_NODE
:
951 ret
= LDP_L2VPN_NODE
;
961 /* Execute command by argument vline vector. */
962 static int cmd_execute_command_real(vector vline
, enum filter_type filter
,
964 const struct cmd_element
**cmd
)
966 struct list
*argv_list
;
967 enum matcher_rv status
;
968 const struct cmd_element
*matched_element
= NULL
;
970 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
971 status
= command_match(cmdgraph
, vline
, &argv_list
, &matched_element
);
974 *cmd
= matched_element
;
976 // if matcher error, return corresponding CMD_ERR
977 if (MATCHER_ERROR(status
)) {
979 list_delete(argv_list
);
981 case MATCHER_INCOMPLETE
:
982 return CMD_ERR_INCOMPLETE
;
983 case MATCHER_AMBIGUOUS
:
984 return CMD_ERR_AMBIGUOUS
;
986 return CMD_ERR_NO_MATCH
;
990 // build argv array from argv list
991 struct cmd_token
**argv
= XMALLOC(
992 MTYPE_TMP
, argv_list
->count
* sizeof(struct cmd_token
*));
994 struct cmd_token
*token
;
996 for (ALL_LIST_ELEMENTS_RO(argv_list
, ln
, token
))
999 int argc
= argv_list
->count
;
1002 if (matched_element
->daemon
)
1003 ret
= CMD_SUCCESS_DAEMON
;
1005 ret
= matched_element
->func(matched_element
, vty
, argc
, argv
);
1007 // delete list and cmd_token's in it
1008 list_delete(argv_list
);
1009 XFREE(MTYPE_TMP
, argv
);
1015 * Execute a given command, handling things like "do ..." and checking
1016 * whether the given command might apply at a parent node if doesn't
1017 * apply for the current node.
1019 * @param vline Command line input, vector of char* where each element is
1021 * @param vty The vty context in which the command should be executed.
1022 * @param cmd Pointer where the struct cmd_element of the matched command
1023 * will be stored, if any. May be set to NULL if this info is
1025 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1026 * @return The status of the command that has been executed or an error code
1027 * as to why no command could be executed.
1029 int cmd_execute_command(vector vline
, struct vty
*vty
,
1030 const struct cmd_element
**cmd
, int vtysh
)
1032 int ret
, saved_ret
= 0;
1033 enum node_type onode
, try_node
;
1035 onode
= try_node
= vty
->node
;
1037 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
1038 vector shifted_vline
;
1041 vty
->node
= ENABLE_NODE
;
1042 /* We can try it on enable node, cos' the vty is authenticated
1045 shifted_vline
= vector_init(vector_count(vline
));
1047 for (index
= 1; index
< vector_active(vline
); index
++)
1048 vector_set_index(shifted_vline
, index
- 1,
1049 vector_lookup(vline
, index
));
1051 ret
= cmd_execute_command_real(shifted_vline
, FILTER_RELAXED
,
1054 vector_free(shifted_vline
);
1060 cmd_execute_command_real(vline
, FILTER_RELAXED
, vty
, cmd
);
1065 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1066 && ret
!= CMD_NOT_MY_INSTANCE
&& ret
!= CMD_WARNING_CONFIG_FAILED
) {
1067 /* This assumes all nodes above CONFIG_NODE are childs of
1069 while (vty
->node
> CONFIG_NODE
) {
1070 try_node
= node_parent(try_node
);
1071 vty
->node
= try_node
;
1072 ret
= cmd_execute_command_real(vline
, FILTER_RELAXED
,
1074 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
1075 || ret
== CMD_NOT_MY_INSTANCE
1076 || ret
== CMD_WARNING_CONFIG_FAILED
)
1079 /* no command succeeded, reset the vty to the original node */
1083 /* return command status for original node */
1088 * Execute a given command, matching it strictly against the current node.
1089 * This mode is used when reading config files.
1091 * @param vline Command line input, vector of char* where each element is
1093 * @param vty The vty context in which the command should be executed.
1094 * @param cmd Pointer where the struct cmd_element* of the matched command
1095 * will be stored, if any. May be set to NULL if this info is
1097 * @return The status of the command that has been executed or an error code
1098 * as to why no command could be executed.
1100 int cmd_execute_command_strict(vector vline
, struct vty
*vty
,
1101 const struct cmd_element
**cmd
)
1103 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1107 * Parse one line of config, walking up the parse tree attempting to find a
1110 * @param vty The vty context in which the command should be executed.
1111 * @param cmd Pointer where the struct cmd_element* of the match command
1112 * will be stored, if any. May be set to NULL if this info is
1114 * @param use_daemon Boolean to control whether or not we match on
1115 * CMD_SUCCESS_DAEMON
1117 * @return The status of the command that has been executed or an error code
1118 * as to why no command could be executed.
1120 int command_config_read_one_line(struct vty
*vty
,
1121 const struct cmd_element
**cmd
, int use_daemon
)
1127 vline
= cmd_make_strvec(vty
->buf
);
1129 /* In case of comment line */
1133 /* Execute configuration command : this is strict match */
1134 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1136 // Climb the tree and try the command again at each node
1137 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1138 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1139 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1140 && ret
!= CMD_NOT_MY_INSTANCE
1141 && ret
!= CMD_WARNING_CONFIG_FAILED
1142 && vty
->node
!= CONFIG_NODE
) {
1144 saved_node
= vty
->node
;
1146 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1147 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1148 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1149 && vty
->node
> CONFIG_NODE
) {
1150 vty
->node
= node_parent(vty
->node
);
1151 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1154 // If climbing the tree did not work then ignore the command and
1155 // stay at the same node
1156 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1157 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1158 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
) {
1159 vty
->node
= saved_node
;
1163 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1164 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1166 cmd_free_strvec(vline
);
1171 /* Configuration make from file. */
1172 int config_from_file(struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1174 int ret
, error_ret
= 0;
1177 while (fgets(vty
->buf
, VTY_BUFSIZ
, fp
)) {
1181 ret
= command_config_read_one_line(vty
, NULL
, 0);
1183 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1184 && ret
!= CMD_ERR_NOTHING_TODO
)
1195 /* Configuration from terminal */
1196 DEFUN (config_terminal
,
1197 config_terminal_cmd
,
1198 "configure terminal",
1199 "Configuration from vty interface\n"
1200 "Configuration terminal\n")
1202 if (vty_config_lock(vty
))
1203 vty
->node
= CONFIG_NODE
;
1205 vty_out(vty
, "VTY configuration is locked by other VTY\n");
1206 return CMD_WARNING_CONFIG_FAILED
;
1211 /* Enable command */
1215 "Turn on privileged mode command\n")
1217 /* If enable password is NULL, change to ENABLE_NODE */
1218 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
)
1219 || vty
->type
== VTY_SHELL_SERV
)
1220 vty
->node
= ENABLE_NODE
;
1222 vty
->node
= AUTH_ENABLE_NODE
;
1227 /* Disable command */
1231 "Turn off privileged mode command\n")
1233 if (vty
->node
== ENABLE_NODE
)
1234 vty
->node
= VIEW_NODE
;
1238 /* Down vty node level. */
1242 "Exit current mode and down to previous mode\n")
1248 void cmd_exit(struct vty
*vty
)
1250 switch (vty
->node
) {
1256 vty
->status
= VTY_CLOSE
;
1259 vty
->node
= ENABLE_NODE
;
1260 vty_config_unlock(vty
);
1262 case INTERFACE_NODE
:
1275 case LDP_L2VPN_NODE
:
1282 vty
->node
= CONFIG_NODE
;
1285 case BGP_IPV4M_NODE
:
1286 case BGP_IPV4L_NODE
:
1287 case BGP_VPNV4_NODE
:
1288 case BGP_VPNV6_NODE
:
1289 case BGP_VRF_POLICY_NODE
:
1290 case BGP_VNC_DEFAULTS_NODE
:
1291 case BGP_VNC_NVE_GROUP_NODE
:
1292 case BGP_VNC_L2_GROUP_NODE
:
1294 case BGP_IPV6M_NODE
:
1296 case BGP_IPV6L_NODE
:
1297 vty
->node
= BGP_NODE
;
1299 case BGP_EVPN_VNI_NODE
:
1300 vty
->node
= BGP_EVPN_NODE
;
1304 vty
->node
= LDP_NODE
;
1306 case LDP_IPV4_IFACE_NODE
:
1307 vty
->node
= LDP_IPV4_NODE
;
1309 case LDP_IPV6_IFACE_NODE
:
1310 vty
->node
= LDP_IPV6_NODE
;
1312 case LDP_PSEUDOWIRE_NODE
:
1313 vty
->node
= LDP_L2VPN_NODE
;
1315 case KEYCHAIN_KEY_NODE
:
1316 vty
->node
= KEYCHAIN_NODE
;
1318 case LINK_PARAMS_NODE
:
1319 vty
->node
= INTERFACE_NODE
;
1330 "Exit current mode and down to previous mode\n")
1332 return config_exit(self
, vty
, argc
, argv
);
1336 /* End of configuration. */
1340 "End current mode and change to enable mode.")
1342 switch (vty
->node
) {
1345 /* Nothing to do. */
1348 case INTERFACE_NODE
:
1358 case BGP_VRF_POLICY_NODE
:
1359 case BGP_VNC_DEFAULTS_NODE
:
1360 case BGP_VNC_NVE_GROUP_NODE
:
1361 case BGP_VNC_L2_GROUP_NODE
:
1362 case BGP_VPNV4_NODE
:
1363 case BGP_VPNV6_NODE
:
1365 case BGP_IPV4M_NODE
:
1366 case BGP_IPV4L_NODE
:
1368 case BGP_IPV6M_NODE
:
1370 case BGP_EVPN_VNI_NODE
:
1371 case BGP_IPV6L_NODE
:
1378 case LDP_IPV4_IFACE_NODE
:
1379 case LDP_IPV6_IFACE_NODE
:
1380 case LDP_L2VPN_NODE
:
1381 case LDP_PSEUDOWIRE_NODE
:
1384 case KEYCHAIN_KEY_NODE
:
1388 case LINK_PARAMS_NODE
:
1389 vty_config_unlock(vty
);
1390 vty
->node
= ENABLE_NODE
;
1399 DEFUN (show_version
,
1403 "Displays zebra version\n")
1405 vty_out(vty
, "%s %s (%s).\n", FRR_FULL_NAME
, FRR_VERSION
,
1406 host
.name
? host
.name
: "");
1407 vty_out(vty
, "%s%s\n", FRR_COPYRIGHT
, GIT_INFO
);
1408 vty_out(vty
, "configured with:\n %s\n", FRR_CONFIG_ARGS
);
1413 /* "Set" version ... ignore version tags */
1414 DEFUN (frr_version_defaults
,
1415 frr_version_defaults_cmd
,
1416 "frr <version|defaults> LINE...",
1417 "FRRouting global parameters\n"
1418 "version configuration was written by\n"
1419 "set of configuration defaults used\n"
1425 /* Help display function for all node. */
1429 "Description of the interactive help system\n")
1432 "Quagga VTY provides advanced help feature. When you need help,\n\
1433 anytime at the command line please press '?'.\n\
1435 If nothing matches, the help list will be empty and you must backup\n\
1436 until entering a '?' shows the available options.\n\
1437 Two styles of help are provided:\n\
1438 1. Full help is available when you are ready to enter a\n\
1439 command argument (e.g. 'show ?') and describes each possible\n\
1441 2. Partial help is provided when an abbreviated argument is entered\n\
1442 and you want to know what arguments match the input\n\
1443 (e.g. 'show me?'.)\n\n");
1447 static void permute(struct graph_node
*start
, struct vty
*vty
)
1449 static struct list
*position
= NULL
;
1451 position
= list_new();
1453 struct cmd_token
*stok
= start
->data
;
1454 struct graph_node
*gnn
;
1455 struct listnode
*ln
;
1458 listnode_add(position
, start
);
1459 for (unsigned int i
= 0; i
< vector_active(start
->to
); i
++) {
1460 struct graph_node
*gn
= vector_slot(start
->to
, i
);
1461 struct cmd_token
*tok
= gn
->data
;
1462 if (tok
->attr
== CMD_ATTR_HIDDEN
1463 || tok
->attr
== CMD_ATTR_DEPRECATED
)
1465 else if (tok
->type
== END_TKN
|| gn
== start
) {
1467 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
)) {
1468 struct cmd_token
*tt
= gnn
->data
;
1469 if (tt
->type
< SPECIAL_TKN
)
1470 vty_out(vty
, " %s", tt
->text
);
1473 vty_out(vty
, "...");
1477 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1478 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
))
1487 list_delete_node(position
, listtail(position
));
1490 int cmd_list_cmds(struct vty
*vty
, int do_permute
)
1492 struct cmd_node
*node
= vector_slot(cmdvec
, vty
->node
);
1495 permute(vector_slot(node
->cmdgraph
->nodes
, 0), vty
);
1497 /* loop over all commands at this node */
1498 struct cmd_element
*element
= NULL
;
1499 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
);
1501 if ((element
= vector_slot(node
->cmd_vector
, i
))
1502 && element
->attr
!= CMD_ATTR_DEPRECATED
1503 && element
->attr
!= CMD_ATTR_HIDDEN
)
1504 vty_out(vty
, " %s\n", element
->string
);
1509 /* Help display function for all node. */
1512 "list [permutations]",
1513 "Print command list\n"
1514 "Print all possible command permutations\n")
1516 return cmd_list_cmds(vty
, argc
== 2);
1519 DEFUN (show_commandtree
,
1520 show_commandtree_cmd
,
1521 "show commandtree [permutations]",
1523 "Show command tree\n"
1524 "Permutations that we are interested in\n")
1526 return cmd_list_cmds(vty
, argc
== 3);
1529 static void vty_write_config(struct vty
*vty
)
1532 struct cmd_node
*node
;
1534 if (vty
->type
== VTY_TERM
) {
1535 vty_out(vty
, "\nCurrent configuration:\n");
1536 vty_out(vty
, "!\n");
1539 vty_out(vty
, "frr version %s\n", FRR_VER_SHORT
);
1540 vty_out(vty
, "frr defaults %s\n", DFLT_NAME
);
1541 vty_out(vty
, "!\n");
1543 for (i
= 0; i
< vector_active(cmdvec
); i
++)
1544 if ((node
= vector_slot(cmdvec
, i
)) && node
->func
1545 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
)) {
1546 if ((*node
->func
)(vty
))
1547 vty_out(vty
, "!\n");
1550 if (vty
->type
== VTY_TERM
) {
1551 vty_out(vty
, "end\n");
1555 /* Write current configuration into file. */
1557 DEFUN (config_write
,
1559 "write [<file|memory|terminal>]",
1560 "Write running configuration to memory, network, or terminal\n"
1561 "Write to configuration file\n"
1562 "Write configuration currently in memory\n"
1563 "Write configuration to terminal\n")
1567 char *config_file
, *slash
;
1568 char *config_file_tmp
= NULL
;
1569 char *config_file_sav
= NULL
;
1570 int ret
= CMD_WARNING
;
1571 struct vty
*file_vty
;
1572 struct stat conf_stat
;
1574 // if command was 'write terminal' or 'show running-config'
1575 if (argc
== 2 && (strmatch(argv
[idx_type
]->text
, "terminal")
1576 || strmatch(argv
[0]->text
, "show"))) {
1577 vty_write_config(vty
);
1584 /* Check and see if we are operating under vtysh configuration */
1585 if (host
.config
== NULL
) {
1587 "Can't save to configuration file, using vtysh.\n");
1592 config_file
= host
.config
;
1595 #define O_DIRECTORY 0
1597 slash
= strrchr(config_file
, '/');
1599 char *config_dir
= XSTRDUP(MTYPE_TMP
, config_file
);
1600 config_dir
[slash
- config_file
] = '\0';
1601 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1602 XFREE(MTYPE_TMP
, config_dir
);
1604 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1605 /* if dirfd is invalid, directory sync fails, but we're still OK */
1607 config_file_sav
= XMALLOC(
1608 MTYPE_TMP
, strlen(config_file
) + strlen(CONF_BACKUP_EXT
) + 1);
1609 strcpy(config_file_sav
, config_file
);
1610 strcat(config_file_sav
, CONF_BACKUP_EXT
);
1613 config_file_tmp
= XMALLOC(MTYPE_TMP
, strlen(config_file
) + 8);
1614 sprintf(config_file_tmp
, "%s.XXXXXX", config_file
);
1616 /* Open file to configuration write. */
1617 fd
= mkstemp(config_file_tmp
);
1619 vty_out(vty
, "Can't open configuration file %s.\n",
1623 if (fchmod(fd
, CONFIGFILE_MASK
) != 0) {
1624 vty_out(vty
, "Can't chmod configuration file %s: %s (%d).\n",
1625 config_file_tmp
, safe_strerror(errno
), errno
);
1629 /* Make vty for configuration file. */
1630 file_vty
= vty_new();
1632 file_vty
->type
= VTY_FILE
;
1634 /* Config file header print. */
1635 vty_out(file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1636 vty_time_print(file_vty
, 1);
1637 vty_out(file_vty
, "!\n");
1638 vty_write_config(file_vty
);
1639 vty_close(file_vty
);
1641 if (stat(config_file
, &conf_stat
) >= 0) {
1642 if (unlink(config_file_sav
) != 0)
1643 if (errno
!= ENOENT
) {
1645 "Can't unlink backup configuration file %s.\n",
1649 if (link(config_file
, config_file_sav
) != 0) {
1651 "Can't backup old configuration file %s.\n",
1658 if (rename(config_file_tmp
, config_file
) != 0) {
1659 vty_out(vty
, "Can't save configuration file %s.\n",
1666 vty_out(vty
, "Configuration saved to %s\n", config_file
);
1670 if (ret
!= CMD_SUCCESS
)
1671 unlink(config_file_tmp
);
1674 XFREE(MTYPE_TMP
, config_file_tmp
);
1675 XFREE(MTYPE_TMP
, config_file_sav
);
1679 /* ALIAS_FIXME for 'write <terminal|memory>' */
1680 DEFUN (show_running_config
,
1681 show_running_config_cmd
,
1682 "show running-config",
1684 "running configuration (same as write terminal/memory)\n")
1686 return config_write(self
, vty
, argc
, argv
);
1689 /* ALIAS_FIXME for 'write file' */
1690 DEFUN (copy_runningconf_startupconf
,
1691 copy_runningconf_startupconf_cmd
,
1692 "copy running-config startup-config",
1693 "Copy configuration\n"
1694 "Copy running config to... \n"
1695 "Copy running config to startup config (same as write file)\n")
1698 vty_write_config(vty
);
1703 /* Write startup configuration into the terminal. */
1704 DEFUN (show_startup_config
,
1705 show_startup_config_cmd
,
1706 "show startup-config",
1708 "Contents of startup configuration\n")
1715 if (host
.config
== NULL
)
1718 confp
= fopen(host
.config
, "r");
1719 if (confp
== NULL
) {
1720 vty_out(vty
, "Can't open configuration file [%s] due to '%s'\n",
1721 host
.config
, safe_strerror(errno
));
1725 while (fgets(buf
, BUFSIZ
, confp
)) {
1728 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1732 vty_out(vty
, "%s\n", buf
);
1740 int cmd_hostname_set(const char *hostname
)
1742 XFREE(MTYPE_HOST
, host
.name
);
1743 host
.name
= hostname
? XSTRDUP(MTYPE_HOST
, hostname
) : NULL
;
1747 /* Hostname configuration */
1748 DEFUN (config_hostname
,
1751 "Set system's network name\n"
1752 "This system's network name\n")
1754 struct cmd_token
*word
= argv
[1];
1756 if (!isalpha((int)word
->arg
[0])) {
1757 vty_out(vty
, "Please specify string starting with alphabet\n");
1758 return CMD_WARNING_CONFIG_FAILED
;
1761 return cmd_hostname_set(word
->arg
);
1764 DEFUN (config_no_hostname
,
1766 "no hostname [HOSTNAME]",
1768 "Reset system's network name\n"
1769 "Host name of this router\n")
1771 return cmd_hostname_set(NULL
);
1774 /* VTY interface password set. */
1775 DEFUN (config_password
,
1777 "password [(8-8)] WORD",
1778 "Assign the terminal connection password\n"
1779 "Specifies a HIDDEN password will follow\n"
1780 "The password string\n")
1784 if (argc
== 3) // '8' was specified
1787 XFREE(MTYPE_HOST
, host
.password
);
1788 host
.password
= NULL
;
1789 if (host
.password_encrypt
)
1790 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1791 host
.password_encrypt
=
1792 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1796 if (!isalnum(argv
[idx_8
]->arg
[0])) {
1798 "Please specify string starting with alphanumeric\n");
1799 return CMD_WARNING_CONFIG_FAILED
;
1803 XFREE(MTYPE_HOST
, host
.password
);
1804 host
.password
= NULL
;
1807 if (host
.password_encrypt
)
1808 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1809 host
.password_encrypt
=
1810 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1812 host
.password
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1817 /* VTY enable password set. */
1818 DEFUN (config_enable_password
,
1819 enable_password_cmd
,
1820 "enable password [(8-8)] WORD",
1821 "Modify enable password parameters\n"
1822 "Assign the privileged level password\n"
1823 "Specifies a HIDDEN password will follow\n"
1824 "The HIDDEN 'enable' password string\n")
1829 /* Crypt type is specified. */
1831 if (argv
[idx_8
]->arg
[0] == '8') {
1833 XFREE(MTYPE_HOST
, host
.enable
);
1836 if (host
.enable_encrypt
)
1837 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1838 host
.enable_encrypt
=
1839 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1843 vty_out(vty
, "Unknown encryption type.\n");
1844 return CMD_WARNING_CONFIG_FAILED
;
1848 if (!isalnum(argv
[idx_8
]->arg
[0])) {
1850 "Please specify string starting with alphanumeric\n");
1851 return CMD_WARNING_CONFIG_FAILED
;
1855 XFREE(MTYPE_HOST
, host
.enable
);
1858 /* Plain password input. */
1860 if (host
.enable_encrypt
)
1861 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1862 host
.enable_encrypt
=
1863 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1865 host
.enable
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1870 /* VTY enable password delete. */
1871 DEFUN (no_config_enable_password
,
1872 no_enable_password_cmd
,
1873 "no enable password",
1875 "Modify enable password parameters\n"
1876 "Assign the privileged level password\n")
1879 XFREE(MTYPE_HOST
, host
.enable
);
1882 if (host
.enable_encrypt
)
1883 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1884 host
.enable_encrypt
= NULL
;
1889 DEFUN (service_password_encrypt
,
1890 service_password_encrypt_cmd
,
1891 "service password-encryption",
1892 "Set up miscellaneous service\n"
1893 "Enable encrypted passwords\n")
1900 if (host
.password
) {
1901 if (host
.password_encrypt
)
1902 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1903 host
.password_encrypt
=
1904 XSTRDUP(MTYPE_HOST
, zencrypt(host
.password
));
1907 if (host
.enable_encrypt
)
1908 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1909 host
.enable_encrypt
=
1910 XSTRDUP(MTYPE_HOST
, zencrypt(host
.enable
));
1916 DEFUN (no_service_password_encrypt
,
1917 no_service_password_encrypt_cmd
,
1918 "no service password-encryption",
1920 "Set up miscellaneous service\n"
1921 "Enable encrypted passwords\n")
1928 if (host
.password_encrypt
)
1929 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1930 host
.password_encrypt
= NULL
;
1932 if (host
.enable_encrypt
)
1933 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1934 host
.enable_encrypt
= NULL
;
1939 DEFUN (config_terminal_length
,
1940 config_terminal_length_cmd
,
1941 "terminal length (0-512)",
1942 "Set terminal line parameters\n"
1943 "Set number of lines on a screen\n"
1944 "Number of lines on screen (0 for no pausing)\n")
1948 vty
->lines
= atoi(argv
[idx_number
]->arg
);
1953 DEFUN (config_terminal_no_length
,
1954 config_terminal_no_length_cmd
,
1955 "terminal no length",
1956 "Set terminal line parameters\n"
1958 "Set number of lines on a screen\n")
1964 DEFUN (service_terminal_length
,
1965 service_terminal_length_cmd
,
1966 "service terminal-length (0-512)",
1967 "Set up miscellaneous service\n"
1968 "System wide terminal length configuration\n"
1969 "Number of lines of VTY (0 means no line control)\n")
1973 host
.lines
= atoi(argv
[idx_number
]->arg
);
1978 DEFUN (no_service_terminal_length
,
1979 no_service_terminal_length_cmd
,
1980 "no service terminal-length [(0-512)]",
1982 "Set up miscellaneous service\n"
1983 "System wide terminal length configuration\n"
1984 "Number of lines of VTY (0 means no line control)\n")
1990 DEFUN_HIDDEN (do_echo
,
1993 "Echo a message back to the vty\n"
1994 "The message to echo\n")
1998 vty_out(vty
, "%s\n",
1999 ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
2001 XFREE(MTYPE_TMP
, message
);
2005 DEFUN (config_logmsg
,
2007 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
2008 "Send a message to enabled logging destinations\n"
2010 "The message to send\n")
2012 int idx_log_level
= 1;
2013 int idx_message
= 2;
2017 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2018 return CMD_ERR_NO_MATCH
;
2021 ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2023 XFREE(MTYPE_TMP
, message
);
2028 DEFUN (show_logging
,
2032 "Show current logging configuration\n")
2034 struct zlog
*zl
= zlog_default
;
2036 vty_out(vty
, "Syslog logging: ");
2037 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2038 vty_out(vty
, "disabled");
2040 vty_out(vty
, "level %s, facility %s, ident %s",
2041 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2042 facility_name(zl
->facility
), zl
->ident
);
2045 vty_out(vty
, "Stdout logging: ");
2046 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2047 vty_out(vty
, "disabled");
2049 vty_out(vty
, "level %s",
2050 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2053 vty_out(vty
, "Monitor logging: ");
2054 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2055 vty_out(vty
, "disabled");
2057 vty_out(vty
, "level %s",
2058 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2061 vty_out(vty
, "File logging: ");
2062 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) || !zl
->fp
)
2063 vty_out(vty
, "disabled");
2065 vty_out(vty
, "level %s, filename %s",
2066 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2070 vty_out(vty
, "Protocol name: %s\n", zl
->protoname
);
2071 vty_out(vty
, "Record priority: %s\n",
2072 (zl
->record_priority
? "enabled" : "disabled"));
2073 vty_out(vty
, "Timestamp precision: %d\n", zl
->timestamp_precision
);
2078 DEFUN (config_log_stdout
,
2079 config_log_stdout_cmd
,
2080 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2082 "Set stdout logging level\n"
2085 int idx_log_level
= 2;
2087 if (argc
== idx_log_level
) {
2088 zlog_set_level(ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2093 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2094 return CMD_ERR_NO_MATCH
;
2095 zlog_set_level(ZLOG_DEST_STDOUT
, level
);
2099 DEFUN (no_config_log_stdout
,
2100 no_config_log_stdout_cmd
,
2101 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2104 "Cancel logging to stdout\n"
2107 zlog_set_level(ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2111 DEFUN (config_log_monitor
,
2112 config_log_monitor_cmd
,
2113 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2115 "Set terminal line (monitor) logging level\n"
2118 int idx_log_level
= 2;
2120 if (argc
== idx_log_level
) {
2121 zlog_set_level(ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2126 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2127 return CMD_ERR_NO_MATCH
;
2128 zlog_set_level(ZLOG_DEST_MONITOR
, level
);
2132 DEFUN (no_config_log_monitor
,
2133 no_config_log_monitor_cmd
,
2134 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2137 "Disable terminal line (monitor) logging\n"
2140 zlog_set_level(ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2144 static int set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2148 const char *fullpath
;
2150 /* Path detection. */
2151 if (!IS_DIRECTORY_SEP(*fname
)) {
2152 char cwd
[MAXPATHLEN
+ 1];
2153 cwd
[MAXPATHLEN
] = '\0';
2155 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
2156 zlog_err("config_log_file: Unable to alloc mem!");
2157 return CMD_WARNING_CONFIG_FAILED
;
2160 if ((p
= XMALLOC(MTYPE_TMP
, strlen(cwd
) + strlen(fname
) + 2))
2162 zlog_err("config_log_file: Unable to alloc mem!");
2163 return CMD_WARNING_CONFIG_FAILED
;
2165 sprintf(p
, "%s/%s", cwd
, fname
);
2170 ret
= zlog_set_file(fullpath
, loglevel
);
2173 XFREE(MTYPE_TMP
, p
);
2176 vty_out(vty
, "can't open logfile %s\n", fname
);
2177 return CMD_WARNING_CONFIG_FAILED
;
2181 XFREE(MTYPE_HOST
, host
.logfile
);
2183 host
.logfile
= XSTRDUP(MTYPE_HOST
, fname
);
2185 #if defined(HAVE_CUMULUS)
2186 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2187 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2192 DEFUN (config_log_file
,
2193 config_log_file_cmd
,
2194 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2197 "Logging filename\n"
2200 int idx_filename
= 2;
2201 int idx_log_levels
= 3;
2204 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2206 return CMD_ERR_NO_MATCH
;
2207 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2209 return set_log_file(vty
, argv
[idx_filename
]->arg
,
2210 zlog_default
->default_lvl
);
2213 DEFUN (no_config_log_file
,
2214 no_config_log_file_cmd
,
2215 "no log file [FILENAME [LEVEL]]",
2218 "Cancel logging to file\n"
2219 "Logging file name\n"
2225 XFREE(MTYPE_HOST
, host
.logfile
);
2227 host
.logfile
= NULL
;
2232 DEFUN (config_log_syslog
,
2233 config_log_syslog_cmd
,
2234 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2236 "Set syslog logging level\n"
2239 int idx_log_levels
= 2;
2242 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2244 return CMD_ERR_NO_MATCH
;
2245 zlog_set_level(ZLOG_DEST_SYSLOG
, level
);
2248 zlog_set_level(ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2253 DEFUN (no_config_log_syslog
,
2254 no_config_log_syslog_cmd
,
2255 "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>]",
2258 "Cancel logging to syslog\n"
2262 zlog_set_level(ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2266 DEFUN (config_log_facility
,
2267 config_log_facility_cmd
,
2268 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2270 "Facility parameter for syslog messages\n"
2274 int facility
= facility_match(argv
[idx_target
]->arg
);
2276 zlog_default
->facility
= facility
;
2280 DEFUN (no_config_log_facility
,
2281 no_config_log_facility_cmd
,
2282 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2285 "Reset syslog facility to default (daemon)\n"
2288 zlog_default
->facility
= LOG_DAEMON
;
2293 config_log_trap
, config_log_trap_cmd
,
2294 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2296 "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC
)
2301 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2302 return CMD_ERR_NO_MATCH
;
2304 zlog_default
->default_lvl
= new_level
;
2305 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2306 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2307 zlog_default
->maxlvl
[i
] = new_level
;
2312 no_config_log_trap
, no_config_log_trap_cmd
,
2313 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2316 "Permit all logging information\n" LOG_LEVEL_DESC
)
2318 zlog_default
->default_lvl
= LOG_DEBUG
;
2322 DEFUN (config_log_record_priority
,
2323 config_log_record_priority_cmd
,
2324 "log record-priority",
2326 "Log the priority of the message within the message\n")
2328 zlog_default
->record_priority
= 1;
2332 DEFUN (no_config_log_record_priority
,
2333 no_config_log_record_priority_cmd
,
2334 "no log record-priority",
2337 "Do not log the priority of the message within the message\n")
2339 zlog_default
->record_priority
= 0;
2343 DEFUN (config_log_timestamp_precision
,
2344 config_log_timestamp_precision_cmd
,
2345 "log timestamp precision (0-6)",
2347 "Timestamp configuration\n"
2348 "Set the timestamp precision\n"
2349 "Number of subsecond digits\n")
2352 zlog_default
->timestamp_precision
=
2353 strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2357 DEFUN (no_config_log_timestamp_precision
,
2358 no_config_log_timestamp_precision_cmd
,
2359 "no log timestamp precision",
2362 "Timestamp configuration\n"
2363 "Reset the timestamp precision to the default value of 0\n")
2365 zlog_default
->timestamp_precision
= 0;
2369 int cmd_banner_motd_file(const char *file
)
2371 int success
= CMD_SUCCESS
;
2376 rpath
= realpath(file
, p
);
2378 return CMD_ERR_NO_FILE
;
2379 in
= strstr(rpath
, SYSCONFDIR
);
2382 XFREE(MTYPE_HOST
, host
.motdfile
);
2383 host
.motdfile
= XSTRDUP(MTYPE_HOST
, file
);
2385 success
= CMD_WARNING_CONFIG_FAILED
;
2390 DEFUN (banner_motd_file
,
2391 banner_motd_file_cmd
,
2392 "banner motd file FILE",
2395 "Banner from a file\n"
2399 const char *filename
= argv
[idx_file
]->arg
;
2400 int cmd
= cmd_banner_motd_file(filename
);
2402 if (cmd
== CMD_ERR_NO_FILE
)
2403 vty_out(vty
, "%s does not exist", filename
);
2404 else if (cmd
== CMD_WARNING_CONFIG_FAILED
)
2405 vty_out(vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2410 DEFUN (banner_motd_default
,
2411 banner_motd_default_cmd
,
2412 "banner motd default",
2413 "Set banner string\n"
2414 "Strings for motd\n"
2417 host
.motd
= default_motd
;
2421 DEFUN (no_banner_motd
,
2425 "Set banner string\n"
2426 "Strings for motd\n")
2430 XFREE(MTYPE_HOST
, host
.motdfile
);
2431 host
.motdfile
= NULL
;
2438 "Find CLI command containing text\n"
2439 "Text to search for\n")
2441 char *text
= argv_concat(argv
, argc
, 1);
2442 const struct cmd_node
*node
;
2443 const struct cmd_element
*cli
;
2446 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++) {
2447 node
= vector_slot(cmdvec
, i
);
2450 clis
= node
->cmd_vector
;
2451 for (unsigned int j
= 0; j
< vector_active(clis
); j
++) {
2452 cli
= vector_slot(clis
, j
);
2453 if (strcasestr(cli
->string
, text
))
2454 vty_out(vty
, " (%s) %s\n",
2455 node_names
[node
->node
], cli
->string
);
2459 XFREE(MTYPE_TMP
, text
);
2464 /* Set config filename. Called from vty.c */
2465 void host_config_set(const char *filename
)
2468 XFREE(MTYPE_HOST
, host
.config
);
2469 host
.config
= XSTRDUP(MTYPE_HOST
, filename
);
2472 const char *host_config_get(void)
2477 void install_default(enum node_type node
)
2479 install_element(node
, &config_exit_cmd
);
2480 install_element(node
, &config_quit_cmd
);
2481 install_element(node
, &config_end_cmd
);
2482 install_element(node
, &config_help_cmd
);
2483 install_element(node
, &config_list_cmd
);
2484 install_element(node
, &find_cmd
);
2486 install_element(node
, &config_write_cmd
);
2487 install_element(node
, &show_running_config_cmd
);
2489 install_element(node
, &autocomplete_cmd
);
2492 /* Initialize command interface. Install basic nodes and commands.
2494 * terminal = 0 -- vtysh / no logging, no config control
2495 * terminal = 1 -- normal daemon
2496 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2497 void cmd_init(int terminal
)
2499 if (array_size(node_names
) != NODE_TYPE_MAX
)
2500 assert(!"Update the CLI node description array!");
2504 varhandlers
= list_new();
2506 /* Allocate initial top vector of commands. */
2507 cmdvec
= vector_init(VECTOR_MIN_SIZE
);
2509 /* Default host value settings. */
2511 host
.password
= NULL
;
2513 host
.logfile
= NULL
;
2515 host
.noconfig
= (terminal
< 0);
2517 host
.motd
= default_motd
;
2518 host
.motdfile
= NULL
;
2520 /* Install top nodes. */
2521 install_node(&view_node
, NULL
);
2522 install_node(&enable_node
, NULL
);
2523 install_node(&auth_node
, NULL
);
2524 install_node(&auth_enable_node
, NULL
);
2525 install_node(&config_node
, config_write_host
);
2527 /* Each node's basic commands. */
2528 install_element(VIEW_NODE
, &show_version_cmd
);
2529 install_element(ENABLE_NODE
, &show_startup_config_cmd
);
2532 install_element(VIEW_NODE
, &config_list_cmd
);
2533 install_element(VIEW_NODE
, &config_exit_cmd
);
2534 install_element(VIEW_NODE
, &config_quit_cmd
);
2535 install_element(VIEW_NODE
, &config_help_cmd
);
2536 install_element(VIEW_NODE
, &config_enable_cmd
);
2537 install_element(VIEW_NODE
, &config_terminal_length_cmd
);
2538 install_element(VIEW_NODE
, &config_terminal_no_length_cmd
);
2539 install_element(VIEW_NODE
, &show_logging_cmd
);
2540 install_element(VIEW_NODE
, &show_commandtree_cmd
);
2541 install_element(VIEW_NODE
, &echo_cmd
);
2542 install_element(VIEW_NODE
, &autocomplete_cmd
);
2543 install_element(VIEW_NODE
, &find_cmd
);
2545 install_element(ENABLE_NODE
, &config_end_cmd
);
2546 install_element(ENABLE_NODE
, &config_disable_cmd
);
2547 install_element(ENABLE_NODE
, &config_terminal_cmd
);
2548 install_element(ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2549 install_element(ENABLE_NODE
, &config_write_cmd
);
2550 install_element(ENABLE_NODE
, &show_running_config_cmd
);
2551 install_element(ENABLE_NODE
, &config_logmsg_cmd
);
2553 install_default(CONFIG_NODE
);
2556 workqueue_cmd_init();
2560 install_element(CONFIG_NODE
, &hostname_cmd
);
2561 install_element(CONFIG_NODE
, &no_hostname_cmd
);
2562 install_element(CONFIG_NODE
, &frr_version_defaults_cmd
);
2565 install_element(CONFIG_NODE
, &password_cmd
);
2566 install_element(CONFIG_NODE
, &enable_password_cmd
);
2567 install_element(CONFIG_NODE
, &no_enable_password_cmd
);
2569 install_element(CONFIG_NODE
, &config_log_stdout_cmd
);
2570 install_element(CONFIG_NODE
, &no_config_log_stdout_cmd
);
2571 install_element(CONFIG_NODE
, &config_log_monitor_cmd
);
2572 install_element(CONFIG_NODE
, &no_config_log_monitor_cmd
);
2573 install_element(CONFIG_NODE
, &config_log_file_cmd
);
2574 install_element(CONFIG_NODE
, &no_config_log_file_cmd
);
2575 install_element(CONFIG_NODE
, &config_log_syslog_cmd
);
2576 install_element(CONFIG_NODE
, &no_config_log_syslog_cmd
);
2577 install_element(CONFIG_NODE
, &config_log_facility_cmd
);
2578 install_element(CONFIG_NODE
, &no_config_log_facility_cmd
);
2579 install_element(CONFIG_NODE
, &config_log_trap_cmd
);
2580 install_element(CONFIG_NODE
, &no_config_log_trap_cmd
);
2581 install_element(CONFIG_NODE
, &config_log_record_priority_cmd
);
2582 install_element(CONFIG_NODE
,
2583 &no_config_log_record_priority_cmd
);
2584 install_element(CONFIG_NODE
,
2585 &config_log_timestamp_precision_cmd
);
2586 install_element(CONFIG_NODE
,
2587 &no_config_log_timestamp_precision_cmd
);
2588 install_element(CONFIG_NODE
, &service_password_encrypt_cmd
);
2589 install_element(CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2590 install_element(CONFIG_NODE
, &banner_motd_default_cmd
);
2591 install_element(CONFIG_NODE
, &banner_motd_file_cmd
);
2592 install_element(CONFIG_NODE
, &no_banner_motd_cmd
);
2593 install_element(CONFIG_NODE
, &service_terminal_length_cmd
);
2594 install_element(CONFIG_NODE
, &no_service_terminal_length_cmd
);
2596 vrf_install_commands();
2600 grammar_sandbox_init();
2604 void cmd_terminate()
2606 struct cmd_node
*cmd_node
;
2609 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++)
2610 if ((cmd_node
= vector_slot(cmdvec
, i
)) != NULL
) {
2611 // deleting the graph delets the cmd_element as
2613 graph_delete_graph(cmd_node
->cmdgraph
);
2614 vector_free(cmd_node
->cmd_vector
);
2615 hash_clean(cmd_node
->cmd_hash
, NULL
);
2616 hash_free(cmd_node
->cmd_hash
);
2617 cmd_node
->cmd_hash
= NULL
;
2620 vector_free(cmdvec
);
2625 XFREE(MTYPE_HOST
, host
.name
);
2627 XFREE(MTYPE_HOST
, host
.password
);
2628 if (host
.password_encrypt
)
2629 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2631 XFREE(MTYPE_HOST
, host
.enable
);
2632 if (host
.enable_encrypt
)
2633 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2635 XFREE(MTYPE_HOST
, host
.logfile
);
2637 XFREE(MTYPE_HOST
, host
.motdfile
);
2639 XFREE(MTYPE_HOST
, host
.config
);
2641 list_delete(varhandlers
);