2 * CLI backend interface.
5 * Copyright (C) 2016 Cumulus Networks, Inc.
6 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 * Copyright (C) 2013 by Open Source Routing.
8 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
10 * This file is part of GNU Zebra.
12 * GNU Zebra is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2, or (at your option) any
17 * GNU Zebra is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License along
23 * with this program; see the file COPYING; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <lib/version.h>
39 #include "workqueue.h"
41 #include "command_match.h"
42 #include "command_graph.h"
48 DEFINE_MTYPE(LIB
, HOST
, "Host config")
49 DEFINE_MTYPE(LIB
, STRVEC
, "String vector")
50 DEFINE_MTYPE(LIB
, COMPLETION
, "Completion item")
52 const char *node_names
[] = {
55 "auth enable", // AUTH_ENABLE_NODE,
56 "enable", // ENABLE_NODE,
57 "config", // CONFIG_NODE,
58 "debug", // DEBUG_NODE,
59 "vrf debug", // VRF_DEBUG_NODE,
60 "vnc debug", // DEBUG_VNC_NODE,
62 "keychain", // KEYCHAIN_NODE,
63 "keychain key", // KEYCHAIN_KEY_NODE,
64 "logical-router", // LOGICALROUTER_NODE,
66 "interface", // INTERFACE_NODE,
67 "nexthop-group", // NH_GROUP_NODE,
68 "zebra", // ZEBRA_NODE,
69 "table", // TABLE_NODE,
71 "ripng", // RIPNG_NODE,
72 "babel", // BABEL_NODE,
73 "eigrp", // EIGRP_NODE,
75 "bgp vpnv4", // BGP_VPNV4_NODE,
76 "bgp vpnv6", // BGP_VPNV6_NODE,
77 "bgp ipv4 unicast", // BGP_IPV4_NODE,
78 "bgp ipv4 multicast", // BGP_IPV4M_NODE,
79 "bgp ipv4 labeled unicast", // BGP_IPV4L_NODE,
80 "bgp ipv6", // BGP_IPV6_NODE,
81 "bgp ipv6 multicast", // BGP_IPV6M_NODE,
82 "bgp ipv6 labeled unicast", // BGP_IPV6L_NODE,
83 "bgp vrf policy", // BGP_VRF_POLICY_NODE,
84 "bgp vnc defaults", // BGP_VNC_DEFAULTS_NODE,
85 "bgp vnc nve", // BGP_VNC_NVE_GROUP_NODE,
86 "bgp vnc l2", // BGP_VNC_L2_GROUP_NODE,
87 "rfp defaults", // RFP_DEFAULTS_NODE,
88 "bgp evpn", // BGP_EVPN_NODE,
90 "ospf6", // OSPF6_NODE,
92 "ldp ipv4", // LDP_IPV4_NODE,
93 "ldp ipv6", // LDP_IPV6_NODE,
94 "ldp ipv4 interface", // LDP_IPV4_IFACE_NODE,
95 "ldp ipv6 interface", // LDP_IPV6_IFACE_NODE,
96 "ldp l2vpn", // LDP_L2VPN_NODE,
97 "ldp", // LDP_PSEUDOWIRE_NODE,
99 "static ip", // IP_NODE,
100 "ipv4 access list", // ACCESS_NODE,
101 "ipv4 prefix list", // PREFIX_NODE,
102 "ipv6 access list", // ACCESS_IPV6_NODE,
103 "MAC access list", // ACCESS_MAC_NODE,
104 "ipv6 prefix list", // PREFIX_IPV6_NODE,
105 "as list", // AS_LIST_NODE,
106 "community list", // COMMUNITY_LIST_NODE,
107 "routemap", // RMAP_NODE,
108 "pbr-map", // PBRMAP_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,
119 "bgp ipv4 flowspec", /* BGP_FLOWSPECV4_NODE
121 "bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE
125 /* Command vector which includes some level of command lists. Normally
126 each daemon maintains each own cmdvec. */
127 vector cmdvec
= NULL
;
129 /* Host information structure. */
133 * Returns host.name if any, otherwise
134 * it returns the system hostname.
136 const char *cmd_hostname_get(void)
142 * Returns unix domainname
144 const char *cmd_domainname_get(void)
146 return host
.domainname
;
149 /* Standard command node structures. */
150 static struct cmd_node auth_node
= {
151 AUTH_NODE
, "Password: ",
154 static struct cmd_node view_node
= {
158 static struct cmd_node auth_enable_node
= {
159 AUTH_ENABLE_NODE
, "Password: ",
162 static struct cmd_node enable_node
= {
166 static struct cmd_node config_node
= {CONFIG_NODE
, "%s(config)# ", 1};
168 /* Default motd string. */
169 static const char *default_motd
= FRR_DEFAULT_MOTD
;
171 static const struct facility_map
{
175 } syslog_facilities
[] = {
176 {LOG_KERN
, "kern", 1},
177 {LOG_USER
, "user", 2},
178 {LOG_MAIL
, "mail", 1},
179 {LOG_DAEMON
, "daemon", 1},
180 {LOG_AUTH
, "auth", 1},
181 {LOG_SYSLOG
, "syslog", 1},
183 {LOG_NEWS
, "news", 1},
184 {LOG_UUCP
, "uucp", 2},
185 {LOG_CRON
, "cron", 1},
189 {LOG_LOCAL0
, "local0", 6},
190 {LOG_LOCAL1
, "local1", 6},
191 {LOG_LOCAL2
, "local2", 6},
192 {LOG_LOCAL3
, "local3", 6},
193 {LOG_LOCAL4
, "local4", 6},
194 {LOG_LOCAL5
, "local5", 6},
195 {LOG_LOCAL6
, "local6", 6},
196 {LOG_LOCAL7
, "local7", 6},
200 static const char *facility_name(int facility
)
202 const struct facility_map
*fm
;
204 for (fm
= syslog_facilities
; fm
->name
; fm
++)
205 if (fm
->facility
== facility
)
210 static int facility_match(const char *str
)
212 const struct facility_map
*fm
;
214 for (fm
= syslog_facilities
; fm
->name
; fm
++)
215 if (!strncmp(str
, fm
->name
, fm
->match
))
220 static int level_match(const char *s
)
224 for (level
= 0; zlog_priority
[level
] != NULL
; level
++)
225 if (!strncmp(s
, zlog_priority
[level
], 2))
227 return ZLOG_DISABLED
;
230 /* This is called from main when a daemon is invoked with -v or --version. */
231 void print_version(const char *progname
)
233 printf("%s version %s\n", progname
, FRR_VERSION
);
234 printf("%s\n", FRR_COPYRIGHT
);
235 printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
239 /* Utility function to concatenate argv argument into a single string
240 with inserting ' ' character between each argument. */
241 char *argv_concat(struct cmd_token
**argv
, int argc
, int shift
)
249 for (i
= shift
; i
< argc
; i
++)
250 len
+= strlen(argv
[i
]->arg
) + 1;
253 p
= str
= XMALLOC(MTYPE_TMP
, len
);
254 for (i
= shift
; i
< argc
; i
++) {
256 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
265 * Convenience function for accessing argv data.
269 * @param text definition snippet of the desired token
270 * @param index the starting index, and where to store the
271 * index of the found token if it exists
272 * @return 1 if found, 0 otherwise
274 int argv_find(struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
277 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
278 if ((found
= strmatch(text
, argv
[i
]->text
)))
283 static unsigned int cmd_hash_key(void *p
)
285 int size
= sizeof(p
);
287 return jhash(p
, size
, 0);
290 static int cmd_hash_cmp(const void *a
, const void *b
)
295 /* Install top node of command vector. */
296 void install_node(struct cmd_node
*node
, int (*func
)(struct vty
*))
298 vector_set_index(cmdvec
, node
->node
, node
);
300 node
->cmdgraph
= graph_new();
301 node
->cmd_vector
= vector_init(VECTOR_MIN_SIZE
);
303 struct cmd_token
*token
=
304 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
305 graph_new_node(node
->cmdgraph
, token
,
306 (void (*)(void *)) & cmd_token_del
);
307 node
->cmd_hash
= hash_create_size(16, cmd_hash_key
, cmd_hash_cmp
,
312 * Tokenizes a string, storing tokens in a vector.
313 * Whitespace is ignored.
315 * Delimiter string = " \n\r\t".
317 * @param string to tokenize
318 * @return tokenized string
320 vector
cmd_make_strvec(const char *string
)
325 char *copy
, *copystart
;
326 copystart
= copy
= XSTRDUP(MTYPE_TMP
, string
);
328 // skip leading whitespace
329 while (isspace((int)*copy
) && *copy
!= '\0')
332 // if the entire string was whitespace or a comment, return
333 if (*copy
== '\0' || *copy
== '!' || *copy
== '#') {
334 XFREE(MTYPE_TMP
, copystart
);
338 vector strvec
= vector_init(VECTOR_MIN_SIZE
);
339 const char *delim
= " \n\r\t", *tok
= NULL
;
341 tok
= strsep(©
, delim
);
343 vector_set(strvec
, XSTRDUP(MTYPE_STRVEC
, tok
));
346 XFREE(MTYPE_TMP
, copystart
);
350 /* Free allocated string vector. */
351 void cmd_free_strvec(vector v
)
359 for (i
= 0; i
< vector_active(v
); i
++)
360 if ((cp
= vector_slot(v
, i
)) != NULL
)
361 XFREE(MTYPE_STRVEC
, cp
);
366 /* Return prompt character of specified node. */
367 const char *cmd_prompt(enum node_type node
)
369 struct cmd_node
*cnode
;
371 cnode
= vector_slot(cmdvec
, node
);
372 return cnode
->prompt
;
375 /* Install a command into a node. */
376 void install_element(enum node_type ntype
, struct cmd_element
*cmd
)
378 struct cmd_node
*cnode
;
380 /* cmd_init hasn't been called */
382 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
387 cnode
= vector_lookup(cmdvec
, ntype
);
392 "\tnode %d (%s) does not exist.\n"
393 "\tplease call install_node() before install_element()\n",
394 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
398 if (hash_lookup(cnode
->cmd_hash
, cmd
) != NULL
) {
401 "\tnode %d (%s) already has this command installed.\n"
402 "\tduplicate install_element call?\n",
403 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
407 assert(hash_get(cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
409 struct graph
*graph
= graph_new();
410 struct cmd_token
*token
=
411 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
412 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
414 cmd_graph_parse(graph
, cmd
);
415 cmd_graph_names(graph
);
416 cmd_graph_merge(cnode
->cmdgraph
, graph
, +1);
417 graph_delete_graph(graph
);
419 vector_set(cnode
->cmd_vector
, cmd
);
421 if (ntype
== VIEW_NODE
)
422 install_element(ENABLE_NODE
, cmd
);
425 void uninstall_element(enum node_type ntype
, struct cmd_element
*cmd
)
427 struct cmd_node
*cnode
;
429 /* cmd_init hasn't been called */
431 fprintf(stderr
, "%s called before cmd_init, breakage likely\n",
436 cnode
= vector_lookup(cmdvec
, ntype
);
441 "\tnode %d (%s) does not exist.\n"
442 "\tplease call install_node() before uninstall_element()\n",
443 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
447 if (hash_release(cnode
->cmd_hash
, cmd
) == NULL
) {
450 "\tnode %d (%s) does not have this command installed.\n"
451 "\tduplicate uninstall_element call?\n",
452 cmd
->name
, cmd
->string
, ntype
, node_names
[ntype
]);
456 vector_unset_value(cnode
->cmd_vector
, cmd
);
458 struct graph
*graph
= graph_new();
459 struct cmd_token
*token
=
460 cmd_token_new(START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
461 graph_new_node(graph
, token
, (void (*)(void *)) & cmd_token_del
);
463 cmd_graph_parse(graph
, cmd
);
464 cmd_graph_names(graph
);
465 cmd_graph_merge(cnode
->cmdgraph
, graph
, -1);
466 graph_delete_graph(graph
);
468 if (ntype
== VIEW_NODE
)
469 uninstall_element(ENABLE_NODE
, cmd
);
473 static const unsigned char itoa64
[] =
474 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
476 static void to64(char *s
, long v
, int n
)
479 *s
++ = itoa64
[v
& 0x3f];
484 static char *zencrypt(const char *passwd
)
488 char *crypt(const char *, const char *);
490 gettimeofday(&tv
, 0);
492 to64(&salt
[0], random(), 3);
493 to64(&salt
[3], tv
.tv_usec
, 3);
496 return crypt(passwd
, salt
);
499 /* This function write configuration of this host. */
500 static int config_write_host(struct vty
*vty
)
502 if (cmd_hostname_get())
503 vty_out(vty
, "hostname %s\n", cmd_hostname_get());
505 if (cmd_domainname_get())
506 vty_out(vty
, "domainname %s\n", cmd_domainname_get());
509 if (host
.password_encrypt
)
510 vty_out(vty
, "password 8 %s\n", host
.password_encrypt
);
511 if (host
.enable_encrypt
)
512 vty_out(vty
, "enable password 8 %s\n",
513 host
.enable_encrypt
);
516 vty_out(vty
, "password %s\n", host
.password
);
518 vty_out(vty
, "enable password %s\n", host
.enable
);
521 if (zlog_default
->default_lvl
!= LOG_DEBUG
) {
522 vty_out(vty
, "! N.B. The 'log trap' command is deprecated.\n");
523 vty_out(vty
, "log trap %s\n",
524 zlog_priority
[zlog_default
->default_lvl
]);
528 && (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
)) {
529 vty_out(vty
, "log file %s", host
.logfile
);
530 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
]
531 != zlog_default
->default_lvl
)
534 [zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
538 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
) {
539 vty_out(vty
, "log stdout");
540 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]
541 != zlog_default
->default_lvl
)
543 zlog_priority
[zlog_default
->maxlvl
544 [ZLOG_DEST_STDOUT
]]);
548 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
549 vty_out(vty
, "no log monitor\n");
550 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]
551 != zlog_default
->default_lvl
)
552 vty_out(vty
, "log monitor %s\n",
553 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]]);
555 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
) {
556 vty_out(vty
, "log syslog");
557 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]
558 != zlog_default
->default_lvl
)
560 zlog_priority
[zlog_default
->maxlvl
561 [ZLOG_DEST_SYSLOG
]]);
565 if (zlog_default
->facility
!= LOG_DAEMON
)
566 vty_out(vty
, "log facility %s\n",
567 facility_name(zlog_default
->facility
));
569 if (zlog_default
->record_priority
== 1)
570 vty_out(vty
, "log record-priority\n");
572 if (zlog_default
->timestamp_precision
> 0)
573 vty_out(vty
, "log timestamp precision %d\n",
574 zlog_default
->timestamp_precision
);
577 vty_out(vty
, "service advanced-vty\n");
580 vty_out(vty
, "service password-encryption\n");
583 vty_out(vty
, "service terminal-length %d\n", host
.lines
);
586 vty_out(vty
, "banner motd file %s\n", host
.motdfile
);
588 vty_out(vty
, "no banner motd\n");
590 if (debug_memstats_at_exit
)
591 vty_out(vty
, "!\ndebug memstats-at-exit\n");
596 /* Utility function for getting command graph. */
597 static struct graph
*cmd_node_graph(vector v
, enum node_type ntype
)
599 struct cmd_node
*cnode
= vector_slot(v
, ntype
);
600 return cnode
->cmdgraph
;
603 static int cmd_try_do_shortcut(enum node_type node
, char *first_word
)
605 if (first_word
!= NULL
&& node
!= AUTH_NODE
&& node
!= VIEW_NODE
606 && node
!= AUTH_ENABLE_NODE
&& 0 == strcmp("do", first_word
))
612 * Compare function for cmd_token.
613 * Used with qsort to sort command completions.
615 static int compare_completions(const void *fst
, const void *snd
)
617 struct cmd_token
*first
= *(struct cmd_token
**)fst
,
618 *secnd
= *(struct cmd_token
**)snd
;
619 return strcmp(first
->text
, secnd
->text
);
623 * Takes a list of completions returned by command_complete,
624 * dedeuplicates them based on both text and description,
625 * sorts them, and returns them as a vector.
627 * @param completions linked list of cmd_token
628 * @return deduplicated and sorted vector with
630 vector
completions_to_vec(struct list
*completions
)
632 vector comps
= vector_init(VECTOR_MIN_SIZE
);
635 struct cmd_token
*token
, *cr
= NULL
;
636 unsigned int i
, exists
;
637 for (ALL_LIST_ELEMENTS_RO(completions
, ln
, token
)) {
638 if (token
->type
== END_TKN
&& (cr
= token
))
641 // linear search for token in completions vector
643 for (i
= 0; i
< vector_active(comps
) && !exists
; i
++) {
644 struct cmd_token
*curr
= vector_slot(comps
, i
);
646 exists
= !strcmp(curr
->text
, token
->text
)
647 && !strcmp(curr
->desc
, token
->desc
);
649 exists
= !strcmp(curr
->text
, token
->text
);
650 #endif /* VTYSH_DEBUG */
654 vector_set(comps
, token
);
658 qsort(comps
->index
, vector_active(comps
), sizeof(void *),
659 &compare_completions
);
661 // make <cr> the first element, if it is present
663 vector_set_index(comps
, vector_active(comps
), NULL
);
664 memmove(comps
->index
+ 1, comps
->index
,
665 (comps
->alloced
- 1) * sizeof(void *));
666 vector_set_index(comps
, 0, cr
);
672 * Generates a vector of cmd_token representing possible completions
673 * on the current input.
675 * @param vline the vectorized input line
676 * @param vty the vty with the node to match on
677 * @param status pointer to matcher status code
678 * @return vector of struct cmd_token * with possible completions
680 static vector
cmd_complete_command_real(vector vline
, struct vty
*vty
,
683 struct list
*completions
;
684 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
686 enum matcher_rv rv
= command_complete(cmdgraph
, vline
, &completions
);
688 if (MATCHER_ERROR(rv
)) {
689 *status
= CMD_ERR_NO_MATCH
;
693 vector comps
= completions_to_vec(completions
);
694 list_delete_and_null(&completions
);
696 // set status code appropriately
697 switch (vector_active(comps
)) {
699 *status
= CMD_ERR_NO_MATCH
;
702 *status
= CMD_COMPLETE_FULL_MATCH
;
705 *status
= CMD_COMPLETE_LIST_MATCH
;
711 vector
cmd_describe_command(vector vline
, struct vty
*vty
, int *status
)
715 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
716 enum node_type onode
;
717 vector shifted_vline
;
721 vty
->node
= ENABLE_NODE
;
722 /* We can try it on enable node, cos' the vty is authenticated
725 shifted_vline
= vector_init(vector_count(vline
));
727 for (index
= 1; index
< vector_active(vline
); index
++) {
728 vector_set_index(shifted_vline
, index
- 1,
729 vector_lookup(vline
, index
));
732 ret
= cmd_complete_command_real(shifted_vline
, vty
, status
);
734 vector_free(shifted_vline
);
739 return cmd_complete_command_real(vline
, vty
, status
);
742 static struct list
*varhandlers
= NULL
;
744 void cmd_variable_complete(struct cmd_token
*token
, const char *arg
,
748 const struct cmd_variable_handler
*cvh
;
752 tmpcomps
= arg
? vector_init(VECTOR_MIN_SIZE
) : comps
;
754 for (ALL_LIST_ELEMENTS_RO(varhandlers
, ln
, cvh
)) {
755 if (cvh
->tokenname
&& strcmp(cvh
->tokenname
, token
->text
))
757 if (cvh
->varname
&& (!token
->varname
758 || strcmp(cvh
->varname
, token
->varname
)))
760 cvh
->completions(tmpcomps
, token
);
768 for (i
= vector_active(tmpcomps
); i
; i
--) {
769 char *item
= vector_slot(tmpcomps
, i
- 1);
770 if (strlen(item
) >= argsz
&& !strncmp(item
, arg
, argsz
))
771 vector_set(comps
, item
);
773 XFREE(MTYPE_COMPLETION
, item
);
775 vector_free(tmpcomps
);
778 #define AUTOCOMP_INDENT 5
780 char *cmd_variable_comp2str(vector comps
, unsigned short cols
)
783 char *buf
= XCALLOC(MTYPE_TMP
, bsz
);
784 int lc
= AUTOCOMP_INDENT
;
785 size_t cs
= AUTOCOMP_INDENT
;
787 snprintf(buf
, bsz
, "%*s", AUTOCOMP_INDENT
, "");
788 for (size_t j
= 0; j
< vector_active(comps
); j
++) {
789 char *item
= vector_slot(comps
, j
);
790 itemlen
= strlen(item
);
792 if (cs
+ itemlen
+ AUTOCOMP_INDENT
+ 3 >= bsz
)
793 buf
= XREALLOC(MTYPE_TMP
, buf
, (bsz
*= 2));
795 if (lc
+ itemlen
+ 1 >= cols
) {
796 cs
+= snprintf(&buf
[cs
], bsz
- cs
, "\n%*s",
797 AUTOCOMP_INDENT
, "");
798 lc
= AUTOCOMP_INDENT
;
801 size_t written
= snprintf(&buf
[cs
], bsz
- cs
, "%s ", item
);
804 XFREE(MTYPE_COMPLETION
, item
);
805 vector_set_index(comps
, j
, NULL
);
810 void cmd_variable_handler_register(const struct cmd_variable_handler
*cvh
)
815 for (; cvh
->completions
; cvh
++)
816 listnode_add(varhandlers
, (void *)cvh
);
819 DEFUN_HIDDEN (autocomplete
,
821 "autocomplete TYPE TEXT VARNAME",
822 "Autocompletion handler (internal, for vtysh)\n"
825 "cmd_token->varname\n")
827 struct cmd_token tok
;
828 vector comps
= vector_init(32);
831 memset(&tok
, 0, sizeof(tok
));
832 tok
.type
= atoi(argv
[1]->arg
);
833 tok
.text
= argv
[2]->arg
;
834 tok
.varname
= argv
[3]->arg
;
835 if (!strcmp(tok
.varname
, "-"))
838 cmd_variable_complete(&tok
, NULL
, comps
);
840 for (i
= 0; i
< vector_active(comps
); i
++) {
841 char *text
= vector_slot(comps
, i
);
842 vty_out(vty
, "%s\n", text
);
843 XFREE(MTYPE_COMPLETION
, text
);
851 * Generate possible tab-completions for the given input. This function only
852 * returns results that would result in a valid command if used as Readline
853 * completions (as is the case in vtysh). For instance, if the passed vline ends
854 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
856 * @param vline vectorized input line
858 * @param status location to store matcher status code in
859 * @return set of valid strings for use with Readline as tab-completions.
862 char **cmd_complete_command(vector vline
, struct vty
*vty
, int *status
)
865 int original_node
= vty
->node
;
866 vector input_line
= vector_init(vector_count(vline
));
868 // if the first token is 'do' we'll want to execute the command in the
870 int do_shortcut
= cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0));
871 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
873 // construct the input line we'll be matching on
874 unsigned int offset
= (do_shortcut
) ? 1 : 0;
875 for (unsigned index
= 0; index
+ offset
< vector_active(vline
); index
++)
876 vector_set_index(input_line
, index
,
877 vector_lookup(vline
, index
+ offset
));
879 // get token completions -- this is a copying operation
880 vector comps
= NULL
, initial_comps
;
881 initial_comps
= cmd_complete_command_real(input_line
, vty
, status
);
883 if (!MATCHER_ERROR(*status
)) {
884 assert(initial_comps
);
885 // filter out everything that is not suitable for a
887 comps
= vector_init(VECTOR_MIN_SIZE
);
888 for (unsigned int i
= 0; i
< vector_active(initial_comps
);
890 struct cmd_token
*token
= vector_slot(initial_comps
, i
);
891 if (token
->type
== WORD_TKN
)
892 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
,
894 else if (IS_VARYING_TOKEN(token
->type
)) {
895 const char *ref
= vector_lookup(
896 vline
, vector_active(vline
) - 1);
897 cmd_variable_complete(token
, ref
, comps
);
900 vector_free(initial_comps
);
902 // since we filtered results, we need to re-set status code
903 switch (vector_active(comps
)) {
905 *status
= CMD_ERR_NO_MATCH
;
908 *status
= CMD_COMPLETE_FULL_MATCH
;
911 *status
= CMD_COMPLETE_LIST_MATCH
;
914 // copy completions text into an array of char*
915 ret
= XMALLOC(MTYPE_TMP
,
916 (vector_active(comps
) + 1) * sizeof(char *));
918 for (i
= 0; i
< vector_active(comps
); i
++) {
919 ret
[i
] = vector_slot(comps
, i
);
921 // set the last element to NULL, because this array is used in
922 // a Readline completion_generator function which expects NULL
923 // as a sentinel value
927 } else if (initial_comps
)
928 vector_free(initial_comps
);
930 // comps should always be null here
933 // free the adjusted input line
934 vector_free(input_line
);
936 // reset vty->node to its original value
937 vty
->node
= original_node
;
942 /* return parent node */
943 /* MUST eventually converge on CONFIG_NODE */
944 enum node_type
node_parent(enum node_type node
)
948 assert(node
> CONFIG_NODE
);
953 case BGP_FLOWSPECV4_NODE
:
954 case BGP_FLOWSPECV6_NODE
:
955 case BGP_VRF_POLICY_NODE
:
956 case BGP_VNC_DEFAULTS_NODE
:
957 case BGP_VNC_NVE_GROUP_NODE
:
958 case BGP_VNC_L2_GROUP_NODE
:
968 case BGP_EVPN_VNI_NODE
:
971 case KEYCHAIN_KEY_NODE
:
974 case LINK_PARAMS_NODE
:
975 ret
= INTERFACE_NODE
;
981 case LDP_IPV4_IFACE_NODE
:
984 case LDP_IPV6_IFACE_NODE
:
987 case LDP_PSEUDOWIRE_NODE
:
988 ret
= LDP_L2VPN_NODE
;
998 /* Execute command by argument vline vector. */
999 static int cmd_execute_command_real(vector vline
, enum filter_type filter
,
1001 const struct cmd_element
**cmd
)
1003 struct list
*argv_list
;
1004 enum matcher_rv status
;
1005 const struct cmd_element
*matched_element
= NULL
;
1007 struct graph
*cmdgraph
= cmd_node_graph(cmdvec
, vty
->node
);
1008 status
= command_match(cmdgraph
, vline
, &argv_list
, &matched_element
);
1011 *cmd
= matched_element
;
1013 // if matcher error, return corresponding CMD_ERR
1014 if (MATCHER_ERROR(status
)) {
1016 list_delete_and_null(&argv_list
);
1018 case MATCHER_INCOMPLETE
:
1019 return CMD_ERR_INCOMPLETE
;
1020 case MATCHER_AMBIGUOUS
:
1021 return CMD_ERR_AMBIGUOUS
;
1023 return CMD_ERR_NO_MATCH
;
1027 // build argv array from argv list
1028 struct cmd_token
**argv
= XMALLOC(
1029 MTYPE_TMP
, argv_list
->count
* sizeof(struct cmd_token
*));
1030 struct listnode
*ln
;
1031 struct cmd_token
*token
;
1033 for (ALL_LIST_ELEMENTS_RO(argv_list
, ln
, token
))
1036 int argc
= argv_list
->count
;
1039 if (matched_element
->daemon
)
1040 ret
= CMD_SUCCESS_DAEMON
;
1042 ret
= matched_element
->func(matched_element
, vty
, argc
, argv
);
1044 // delete list and cmd_token's in it
1045 list_delete_and_null(&argv_list
);
1046 XFREE(MTYPE_TMP
, argv
);
1052 * Execute a given command, handling things like "do ..." and checking
1053 * whether the given command might apply at a parent node if doesn't
1054 * apply for the current node.
1056 * @param vline Command line input, vector of char* where each element is
1058 * @param vty The vty context in which the command should be executed.
1059 * @param cmd Pointer where the struct cmd_element of the matched command
1060 * will be stored, if any. May be set to NULL if this info is
1062 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1063 * @return The status of the command that has been executed or an error code
1064 * as to why no command could be executed.
1066 int cmd_execute_command(vector vline
, struct vty
*vty
,
1067 const struct cmd_element
**cmd
, int vtysh
)
1069 int ret
, saved_ret
= 0;
1070 enum node_type onode
, try_node
;
1072 onode
= try_node
= vty
->node
;
1074 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0))) {
1075 vector shifted_vline
;
1078 vty
->node
= ENABLE_NODE
;
1079 /* We can try it on enable node, cos' the vty is authenticated
1082 shifted_vline
= vector_init(vector_count(vline
));
1084 for (index
= 1; index
< vector_active(vline
); index
++)
1085 vector_set_index(shifted_vline
, index
- 1,
1086 vector_lookup(vline
, index
));
1088 ret
= cmd_execute_command_real(shifted_vline
, FILTER_RELAXED
,
1091 vector_free(shifted_vline
);
1097 cmd_execute_command_real(vline
, FILTER_RELAXED
, vty
, cmd
);
1102 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1103 && ret
!= CMD_NOT_MY_INSTANCE
&& ret
!= CMD_WARNING_CONFIG_FAILED
) {
1104 /* This assumes all nodes above CONFIG_NODE are childs of
1106 while (vty
->node
> CONFIG_NODE
) {
1107 try_node
= node_parent(try_node
);
1108 vty
->node
= try_node
;
1109 ret
= cmd_execute_command_real(vline
, FILTER_RELAXED
,
1111 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
1112 || ret
== CMD_NOT_MY_INSTANCE
1113 || ret
== CMD_WARNING_CONFIG_FAILED
)
1116 /* no command succeeded, reset the vty to the original node */
1120 /* return command status for original node */
1125 * Execute a given command, matching it strictly against the current node.
1126 * This mode is used when reading config files.
1128 * @param vline Command line input, vector of char* where each element is
1130 * @param vty The vty context in which the command should be executed.
1131 * @param cmd Pointer where the struct cmd_element* of the matched command
1132 * will be stored, if any. May be set to NULL if this info is
1134 * @return The status of the command that has been executed or an error code
1135 * as to why no command could be executed.
1137 int cmd_execute_command_strict(vector vline
, struct vty
*vty
,
1138 const struct cmd_element
**cmd
)
1140 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1144 * Parse one line of config, walking up the parse tree attempting to find a
1147 * @param vty The vty context in which the command should be executed.
1148 * @param cmd Pointer where the struct cmd_element* of the match command
1149 * will be stored, if any. May be set to NULL if this info is
1151 * @param use_daemon Boolean to control whether or not we match on
1152 * CMD_SUCCESS_DAEMON
1154 * @return The status of the command that has been executed or an error code
1155 * as to why no command could be executed.
1157 int command_config_read_one_line(struct vty
*vty
,
1158 const struct cmd_element
**cmd
, int use_daemon
)
1164 vline
= cmd_make_strvec(vty
->buf
);
1166 /* In case of comment line */
1170 /* Execute configuration command : this is strict match */
1171 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1173 // Climb the tree and try the command again at each node
1174 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1175 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1176 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1177 && ret
!= CMD_NOT_MY_INSTANCE
&& ret
!= CMD_WARNING_CONFIG_FAILED
1178 && vty
->node
!= CONFIG_NODE
) {
1180 saved_node
= vty
->node
;
1182 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1183 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1184 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1185 && vty
->node
> CONFIG_NODE
) {
1186 vty
->node
= node_parent(vty
->node
);
1187 ret
= cmd_execute_command_strict(vline
, vty
, cmd
);
1190 // If climbing the tree did not work then ignore the command and
1191 // stay at the same node
1192 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
)
1193 && !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
)
1194 && ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
) {
1195 vty
->node
= saved_node
;
1199 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1200 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1202 cmd_free_strvec(vline
);
1207 /* Configuration make from file. */
1208 int config_from_file(struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1210 int ret
, error_ret
= 0;
1213 while (fgets(vty
->buf
, VTY_BUFSIZ
, fp
)) {
1217 ret
= command_config_read_one_line(vty
, NULL
, 0);
1219 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
1220 && ret
!= CMD_ERR_NOTHING_TODO
)
1231 /* Configuration from terminal */
1232 DEFUN (config_terminal
,
1233 config_terminal_cmd
,
1234 "configure terminal",
1235 "Configuration from vty interface\n"
1236 "Configuration terminal\n")
1238 if (vty_config_lock(vty
))
1239 vty
->node
= CONFIG_NODE
;
1241 vty_out(vty
, "VTY configuration is locked by other VTY\n");
1242 return CMD_WARNING_CONFIG_FAILED
;
1247 /* Enable command */
1251 "Turn on privileged mode command\n")
1253 /* If enable password is NULL, change to ENABLE_NODE */
1254 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
)
1255 || vty
->type
== VTY_SHELL_SERV
)
1256 vty
->node
= ENABLE_NODE
;
1258 vty
->node
= AUTH_ENABLE_NODE
;
1263 /* Disable command */
1267 "Turn off privileged mode command\n")
1269 if (vty
->node
== ENABLE_NODE
)
1270 vty
->node
= VIEW_NODE
;
1274 /* Down vty node level. */
1278 "Exit current mode and down to previous mode\n")
1284 void cmd_exit(struct vty
*vty
)
1286 switch (vty
->node
) {
1292 vty
->status
= VTY_CLOSE
;
1295 vty
->node
= ENABLE_NODE
;
1296 vty_config_unlock(vty
);
1298 case INTERFACE_NODE
:
1300 case LOGICALROUTER_NODE
:
1312 case LDP_L2VPN_NODE
:
1318 vty
->node
= CONFIG_NODE
;
1321 case BGP_IPV4M_NODE
:
1322 case BGP_IPV4L_NODE
:
1323 case BGP_VPNV4_NODE
:
1324 case BGP_VPNV6_NODE
:
1325 case BGP_FLOWSPECV4_NODE
:
1326 case BGP_FLOWSPECV6_NODE
:
1327 case BGP_VRF_POLICY_NODE
:
1328 case BGP_VNC_DEFAULTS_NODE
:
1329 case BGP_VNC_NVE_GROUP_NODE
:
1330 case BGP_VNC_L2_GROUP_NODE
:
1332 case BGP_IPV6M_NODE
:
1334 case BGP_IPV6L_NODE
:
1335 vty
->node
= BGP_NODE
;
1337 case BGP_EVPN_VNI_NODE
:
1338 vty
->node
= BGP_EVPN_NODE
;
1342 vty
->node
= LDP_NODE
;
1344 case LDP_IPV4_IFACE_NODE
:
1345 vty
->node
= LDP_IPV4_NODE
;
1347 case LDP_IPV6_IFACE_NODE
:
1348 vty
->node
= LDP_IPV6_NODE
;
1350 case LDP_PSEUDOWIRE_NODE
:
1351 vty
->node
= LDP_L2VPN_NODE
;
1353 case KEYCHAIN_KEY_NODE
:
1354 vty
->node
= KEYCHAIN_NODE
;
1356 case LINK_PARAMS_NODE
:
1357 vty
->node
= INTERFACE_NODE
;
1368 "Exit current mode and down to previous mode\n")
1370 return config_exit(self
, vty
, argc
, argv
);
1374 /* End of configuration. */
1378 "End current mode and change to enable mode.\n")
1380 switch (vty
->node
) {
1383 /* Nothing to do. */
1386 case INTERFACE_NODE
:
1388 case LOGICALROUTER_NODE
:
1397 case BGP_VRF_POLICY_NODE
:
1398 case BGP_VNC_DEFAULTS_NODE
:
1399 case BGP_VNC_NVE_GROUP_NODE
:
1400 case BGP_VNC_L2_GROUP_NODE
:
1401 case BGP_VPNV4_NODE
:
1402 case BGP_VPNV6_NODE
:
1403 case BGP_FLOWSPECV4_NODE
:
1404 case BGP_FLOWSPECV6_NODE
:
1406 case BGP_IPV4M_NODE
:
1407 case BGP_IPV4L_NODE
:
1409 case BGP_IPV6M_NODE
:
1411 case BGP_EVPN_VNI_NODE
:
1412 case BGP_IPV6L_NODE
:
1420 case LDP_IPV4_IFACE_NODE
:
1421 case LDP_IPV6_IFACE_NODE
:
1422 case LDP_L2VPN_NODE
:
1423 case LDP_PSEUDOWIRE_NODE
:
1426 case KEYCHAIN_KEY_NODE
:
1428 case LINK_PARAMS_NODE
:
1429 vty_config_unlock(vty
);
1430 vty
->node
= ENABLE_NODE
;
1439 DEFUN (show_version
,
1443 "Displays zebra version\n")
1445 vty_out(vty
, "%s %s (%s).\n", FRR_FULL_NAME
, FRR_VERSION
,
1446 cmd_hostname_get() ? cmd_hostname_get() : "");
1447 vty_out(vty
, "%s%s\n", FRR_COPYRIGHT
, GIT_INFO
);
1448 vty_out(vty
, "configured with:\n %s\n", FRR_CONFIG_ARGS
);
1453 /* "Set" version ... ignore version tags */
1454 DEFUN (frr_version_defaults
,
1455 frr_version_defaults_cmd
,
1456 "frr <version|defaults> LINE...",
1457 "FRRouting global parameters\n"
1458 "version configuration was written by\n"
1459 "set of configuration defaults used\n"
1465 /* Help display function for all node. */
1469 "Description of the interactive help system\n")
1472 "Quagga VTY provides advanced help feature. When you need help,\n\
1473 anytime at the command line please press '?'.\n\
1475 If nothing matches, the help list will be empty and you must backup\n\
1476 until entering a '?' shows the available options.\n\
1477 Two styles of help are provided:\n\
1478 1. Full help is available when you are ready to enter a\n\
1479 command argument (e.g. 'show ?') and describes each possible\n\
1481 2. Partial help is provided when an abbreviated argument is entered\n\
1482 and you want to know what arguments match the input\n\
1483 (e.g. 'show me?'.)\n\n");
1487 static void permute(struct graph_node
*start
, struct vty
*vty
)
1489 static struct list
*position
= NULL
;
1491 position
= list_new();
1493 struct cmd_token
*stok
= start
->data
;
1494 struct graph_node
*gnn
;
1495 struct listnode
*ln
;
1498 listnode_add(position
, start
);
1499 for (unsigned int i
= 0; i
< vector_active(start
->to
); i
++) {
1500 struct graph_node
*gn
= vector_slot(start
->to
, i
);
1501 struct cmd_token
*tok
= gn
->data
;
1502 if (tok
->attr
== CMD_ATTR_HIDDEN
1503 || tok
->attr
== CMD_ATTR_DEPRECATED
)
1505 else if (tok
->type
== END_TKN
|| gn
== start
) {
1507 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
)) {
1508 struct cmd_token
*tt
= gnn
->data
;
1509 if (tt
->type
< SPECIAL_TKN
)
1510 vty_out(vty
, " %s", tt
->text
);
1513 vty_out(vty
, "...");
1517 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1518 for (ALL_LIST_ELEMENTS_RO(position
, ln
, gnn
))
1527 list_delete_node(position
, listtail(position
));
1530 int cmd_list_cmds(struct vty
*vty
, int do_permute
)
1532 struct cmd_node
*node
= vector_slot(cmdvec
, vty
->node
);
1535 permute(vector_slot(node
->cmdgraph
->nodes
, 0), vty
);
1537 /* loop over all commands at this node */
1538 struct cmd_element
*element
= NULL
;
1539 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
);
1541 if ((element
= vector_slot(node
->cmd_vector
, i
))
1542 && element
->attr
!= CMD_ATTR_DEPRECATED
1543 && element
->attr
!= CMD_ATTR_HIDDEN
)
1544 vty_out(vty
, " %s\n", element
->string
);
1549 /* Help display function for all node. */
1552 "list [permutations]",
1553 "Print command list\n"
1554 "Print all possible command permutations\n")
1556 return cmd_list_cmds(vty
, argc
== 2);
1559 DEFUN (show_commandtree
,
1560 show_commandtree_cmd
,
1561 "show commandtree [permutations]",
1563 "Show command tree\n"
1564 "Permutations that we are interested in\n")
1566 return cmd_list_cmds(vty
, argc
== 3);
1569 static int vty_write_config(struct vty
*vty
)
1572 struct cmd_node
*node
;
1577 if (vty
->type
== VTY_TERM
) {
1578 vty_out(vty
, "\nCurrent configuration:\n");
1579 vty_out(vty
, "!\n");
1582 vty_out(vty
, "frr version %s\n", FRR_VER_SHORT
);
1583 vty_out(vty
, "frr defaults %s\n", DFLT_NAME
);
1584 vty_out(vty
, "!\n");
1586 for (i
= 0; i
< vector_active(cmdvec
); i
++)
1587 if ((node
= vector_slot(cmdvec
, i
)) && node
->func
1588 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
)) {
1589 if ((*node
->func
)(vty
))
1590 vty_out(vty
, "!\n");
1593 if (vty
->type
== VTY_TERM
) {
1594 vty_out(vty
, "end\n");
1600 static int file_write_config(struct vty
*vty
)
1603 char *config_file
, *slash
;
1604 char *config_file_tmp
= NULL
;
1605 char *config_file_sav
= NULL
;
1606 int ret
= CMD_WARNING
;
1607 struct vty
*file_vty
;
1608 struct stat conf_stat
;
1613 /* Check and see if we are operating under vtysh configuration */
1614 if (host
.config
== NULL
) {
1616 "Can't save to configuration file, using vtysh.\n");
1621 config_file
= host
.config
;
1624 #define O_DIRECTORY 0
1626 slash
= strrchr(config_file
, '/');
1628 char *config_dir
= XSTRDUP(MTYPE_TMP
, config_file
);
1629 config_dir
[slash
- config_file
] = '\0';
1630 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1631 XFREE(MTYPE_TMP
, config_dir
);
1633 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1634 /* if dirfd is invalid, directory sync fails, but we're still OK */
1636 config_file_sav
= XMALLOC(
1637 MTYPE_TMP
, strlen(config_file
) + strlen(CONF_BACKUP_EXT
) + 1);
1638 strcpy(config_file_sav
, config_file
);
1639 strcat(config_file_sav
, CONF_BACKUP_EXT
);
1642 config_file_tmp
= XMALLOC(MTYPE_TMP
, strlen(config_file
) + 8);
1643 sprintf(config_file_tmp
, "%s.XXXXXX", config_file
);
1645 /* Open file to configuration write. */
1646 fd
= mkstemp(config_file_tmp
);
1648 vty_out(vty
, "Can't open configuration file %s.\n",
1652 if (fchmod(fd
, CONFIGFILE_MASK
) != 0) {
1653 vty_out(vty
, "Can't chmod configuration file %s: %s (%d).\n",
1654 config_file_tmp
, safe_strerror(errno
), errno
);
1658 /* Make vty for configuration file. */
1659 file_vty
= vty_new();
1661 file_vty
->type
= VTY_FILE
;
1663 /* Config file header print. */
1664 vty_out(file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1665 vty_time_print(file_vty
, 1);
1666 vty_out(file_vty
, "!\n");
1667 vty_write_config(file_vty
);
1668 vty_close(file_vty
);
1670 if (stat(config_file
, &conf_stat
) >= 0) {
1671 if (unlink(config_file_sav
) != 0)
1672 if (errno
!= ENOENT
) {
1674 "Can't unlink backup configuration file %s.\n",
1678 if (link(config_file
, config_file_sav
) != 0) {
1680 "Can't backup old configuration file %s.\n",
1687 if (rename(config_file_tmp
, config_file
) != 0) {
1688 vty_out(vty
, "Can't save configuration file %s.\n",
1695 vty_out(vty
, "Configuration saved to %s\n", config_file
);
1699 if (ret
!= CMD_SUCCESS
)
1700 unlink(config_file_tmp
);
1703 XFREE(MTYPE_TMP
, config_file_tmp
);
1704 XFREE(MTYPE_TMP
, config_file_sav
);
1708 /* Write current configuration into file. */
1710 DEFUN (config_write
,
1712 "write [<file|memory|terminal>]",
1713 "Write running configuration to memory, network, or terminal\n"
1714 "Write to configuration file\n"
1715 "Write configuration currently in memory\n"
1716 "Write configuration to terminal\n")
1718 const int idx_type
= 1;
1720 // if command was 'write terminal' or 'write memory'
1721 if (argc
== 2 && (!strcmp(argv
[idx_type
]->text
, "terminal"))) {
1722 return vty_write_config(vty
);
1725 return file_write_config(vty
);
1728 /* ALIAS_FIXME for 'write <terminal|memory>' */
1729 DEFUN (show_running_config
,
1730 show_running_config_cmd
,
1731 "show running-config",
1733 "running configuration (same as write terminal)\n")
1735 return vty_write_config(vty
);
1738 /* ALIAS_FIXME for 'write file' */
1739 DEFUN (copy_runningconf_startupconf
,
1740 copy_runningconf_startupconf_cmd
,
1741 "copy running-config startup-config",
1742 "Copy configuration\n"
1743 "Copy running config to... \n"
1744 "Copy running config to startup config (same as write file/memory)\n")
1746 return file_write_config(vty
);
1750 /* Write startup configuration into the terminal. */
1751 DEFUN (show_startup_config
,
1752 show_startup_config_cmd
,
1753 "show startup-config",
1755 "Contents of startup configuration\n")
1762 if (host
.config
== NULL
)
1765 confp
= fopen(host
.config
, "r");
1766 if (confp
== NULL
) {
1767 vty_out(vty
, "Can't open configuration file [%s] due to '%s'\n",
1768 host
.config
, safe_strerror(errno
));
1772 while (fgets(buf
, BUFSIZ
, confp
)) {
1775 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1779 vty_out(vty
, "%s\n", buf
);
1787 int cmd_domainname_set(const char *domainname
)
1789 XFREE(MTYPE_HOST
, host
.domainname
);
1790 host
.domainname
= domainname
? XSTRDUP(MTYPE_HOST
, domainname
) : NULL
;
1794 /* Hostname configuration */
1795 DEFUN(config_domainname
,
1798 "Set system's domain name\n"
1799 "This system's domain name\n")
1801 struct cmd_token
*word
= argv
[1];
1803 if (!isalpha((int)word
->arg
[0])) {
1804 vty_out(vty
, "Please specify string starting with alphabet\n");
1805 return CMD_WARNING_CONFIG_FAILED
;
1808 return cmd_domainname_set(word
->arg
);
1811 DEFUN(config_no_domainname
,
1813 "no domainname [DOMAINNAME]",
1815 "Reset system's domain name\n"
1816 "domain name of this router\n")
1818 return cmd_domainname_set(NULL
);
1821 int cmd_hostname_set(const char *hostname
)
1823 XFREE(MTYPE_HOST
, host
.name
);
1824 host
.name
= hostname
? XSTRDUP(MTYPE_HOST
, hostname
) : NULL
;
1828 /* Hostname configuration */
1829 DEFUN (config_hostname
,
1832 "Set system's network name\n"
1833 "This system's network name\n")
1835 struct cmd_token
*word
= argv
[1];
1837 if (!isalpha((int)word
->arg
[0])) {
1838 vty_out(vty
, "Please specify string starting with alphabet\n");
1839 return CMD_WARNING_CONFIG_FAILED
;
1842 return cmd_hostname_set(word
->arg
);
1845 DEFUN (config_no_hostname
,
1847 "no hostname [HOSTNAME]",
1849 "Reset system's network name\n"
1850 "Host name of this router\n")
1852 return cmd_hostname_set(NULL
);
1855 /* VTY interface password set. */
1856 DEFUN (config_password
,
1858 "password [(8-8)] WORD",
1859 "Assign the terminal connection password\n"
1860 "Specifies a HIDDEN password will follow\n"
1861 "The password string\n")
1865 if (argc
== 3) // '8' was specified
1868 XFREE(MTYPE_HOST
, host
.password
);
1869 host
.password
= NULL
;
1870 if (host
.password_encrypt
)
1871 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1872 host
.password_encrypt
=
1873 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1877 if (!isalnum((int)argv
[idx_8
]->arg
[0])) {
1879 "Please specify string starting with alphanumeric\n");
1880 return CMD_WARNING_CONFIG_FAILED
;
1884 XFREE(MTYPE_HOST
, host
.password
);
1885 host
.password
= NULL
;
1888 if (host
.password_encrypt
)
1889 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1890 host
.password_encrypt
=
1891 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1893 host
.password
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1898 /* VTY enable password set. */
1899 DEFUN (config_enable_password
,
1900 enable_password_cmd
,
1901 "enable password [(8-8)] WORD",
1902 "Modify enable password parameters\n"
1903 "Assign the privileged level password\n"
1904 "Specifies a HIDDEN password will follow\n"
1905 "The HIDDEN 'enable' password string\n")
1910 /* Crypt type is specified. */
1912 if (argv
[idx_8
]->arg
[0] == '8') {
1914 XFREE(MTYPE_HOST
, host
.enable
);
1917 if (host
.enable_encrypt
)
1918 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1919 host
.enable_encrypt
=
1920 XSTRDUP(MTYPE_HOST
, argv
[idx_word
]->arg
);
1924 vty_out(vty
, "Unknown encryption type.\n");
1925 return CMD_WARNING_CONFIG_FAILED
;
1929 if (!isalnum((int)argv
[idx_8
]->arg
[0])) {
1931 "Please specify string starting with alphanumeric\n");
1932 return CMD_WARNING_CONFIG_FAILED
;
1936 XFREE(MTYPE_HOST
, host
.enable
);
1939 /* Plain password input. */
1941 if (host
.enable_encrypt
)
1942 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1943 host
.enable_encrypt
=
1944 XSTRDUP(MTYPE_HOST
, zencrypt(argv
[idx_8
]->arg
));
1946 host
.enable
= XSTRDUP(MTYPE_HOST
, argv
[idx_8
]->arg
);
1951 /* VTY enable password delete. */
1952 DEFUN (no_config_enable_password
,
1953 no_enable_password_cmd
,
1954 "no enable password",
1956 "Modify enable password parameters\n"
1957 "Assign the privileged level password\n")
1960 XFREE(MTYPE_HOST
, host
.enable
);
1963 if (host
.enable_encrypt
)
1964 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1965 host
.enable_encrypt
= NULL
;
1970 DEFUN (service_password_encrypt
,
1971 service_password_encrypt_cmd
,
1972 "service password-encryption",
1973 "Set up miscellaneous service\n"
1974 "Enable encrypted passwords\n")
1981 if (host
.password
) {
1982 if (host
.password_encrypt
)
1983 XFREE(MTYPE_HOST
, host
.password_encrypt
);
1984 host
.password_encrypt
=
1985 XSTRDUP(MTYPE_HOST
, zencrypt(host
.password
));
1988 if (host
.enable_encrypt
)
1989 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
1990 host
.enable_encrypt
=
1991 XSTRDUP(MTYPE_HOST
, zencrypt(host
.enable
));
1997 DEFUN (no_service_password_encrypt
,
1998 no_service_password_encrypt_cmd
,
1999 "no service password-encryption",
2001 "Set up miscellaneous service\n"
2002 "Enable encrypted passwords\n")
2009 if (host
.password_encrypt
)
2010 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2011 host
.password_encrypt
= NULL
;
2013 if (host
.enable_encrypt
)
2014 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2015 host
.enable_encrypt
= NULL
;
2020 DEFUN (config_terminal_length
,
2021 config_terminal_length_cmd
,
2022 "terminal length (0-512)",
2023 "Set terminal line parameters\n"
2024 "Set number of lines on a screen\n"
2025 "Number of lines on screen (0 for no pausing)\n")
2029 vty
->lines
= atoi(argv
[idx_number
]->arg
);
2034 DEFUN (config_terminal_no_length
,
2035 config_terminal_no_length_cmd
,
2036 "terminal no length",
2037 "Set terminal line parameters\n"
2039 "Set number of lines on a screen\n")
2045 DEFUN (service_terminal_length
,
2046 service_terminal_length_cmd
,
2047 "service terminal-length (0-512)",
2048 "Set up miscellaneous service\n"
2049 "System wide terminal length configuration\n"
2050 "Number of lines of VTY (0 means no line control)\n")
2054 host
.lines
= atoi(argv
[idx_number
]->arg
);
2059 DEFUN (no_service_terminal_length
,
2060 no_service_terminal_length_cmd
,
2061 "no service terminal-length [(0-512)]",
2063 "Set up miscellaneous service\n"
2064 "System wide terminal length configuration\n"
2065 "Number of lines of VTY (0 means no line control)\n")
2071 DEFUN_HIDDEN (do_echo
,
2074 "Echo a message back to the vty\n"
2075 "The message to echo\n")
2079 vty_out(vty
, "%s\n",
2080 ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
2082 XFREE(MTYPE_TMP
, message
);
2086 DEFUN (config_logmsg
,
2088 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
2089 "Send a message to enabled logging destinations\n"
2091 "The message to send\n")
2093 int idx_log_level
= 1;
2094 int idx_message
= 2;
2098 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2099 return CMD_ERR_NO_MATCH
;
2102 ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2104 XFREE(MTYPE_TMP
, message
);
2109 DEFUN (show_logging
,
2113 "Show current logging configuration\n")
2115 struct zlog
*zl
= zlog_default
;
2117 vty_out(vty
, "Syslog logging: ");
2118 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2119 vty_out(vty
, "disabled");
2121 vty_out(vty
, "level %s, facility %s, ident %s",
2122 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2123 facility_name(zl
->facility
), zl
->ident
);
2126 vty_out(vty
, "Stdout logging: ");
2127 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2128 vty_out(vty
, "disabled");
2130 vty_out(vty
, "level %s",
2131 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2134 vty_out(vty
, "Monitor logging: ");
2135 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2136 vty_out(vty
, "disabled");
2138 vty_out(vty
, "level %s",
2139 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2142 vty_out(vty
, "File logging: ");
2143 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) || !zl
->fp
)
2144 vty_out(vty
, "disabled");
2146 vty_out(vty
, "level %s, filename %s",
2147 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2151 vty_out(vty
, "Protocol name: %s\n", zl
->protoname
);
2152 vty_out(vty
, "Record priority: %s\n",
2153 (zl
->record_priority
? "enabled" : "disabled"));
2154 vty_out(vty
, "Timestamp precision: %d\n", zl
->timestamp_precision
);
2159 DEFUN (config_log_stdout
,
2160 config_log_stdout_cmd
,
2161 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2163 "Set stdout logging level\n"
2166 int idx_log_level
= 2;
2168 if (argc
== idx_log_level
) {
2169 zlog_set_level(ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2174 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2175 return CMD_ERR_NO_MATCH
;
2176 zlog_set_level(ZLOG_DEST_STDOUT
, level
);
2180 DEFUN (no_config_log_stdout
,
2181 no_config_log_stdout_cmd
,
2182 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2185 "Cancel logging to stdout\n"
2188 zlog_set_level(ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2192 DEFUN (config_log_monitor
,
2193 config_log_monitor_cmd
,
2194 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2196 "Set terminal line (monitor) logging level\n"
2199 int idx_log_level
= 2;
2201 if (argc
== idx_log_level
) {
2202 zlog_set_level(ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2207 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2208 return CMD_ERR_NO_MATCH
;
2209 zlog_set_level(ZLOG_DEST_MONITOR
, level
);
2213 DEFUN (no_config_log_monitor
,
2214 no_config_log_monitor_cmd
,
2215 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2218 "Disable terminal line (monitor) logging\n"
2221 zlog_set_level(ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2225 static int set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2229 const char *fullpath
;
2231 /* Path detection. */
2232 if (!IS_DIRECTORY_SEP(*fname
)) {
2233 char cwd
[MAXPATHLEN
+ 1];
2234 cwd
[MAXPATHLEN
] = '\0';
2236 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
2237 zlog_err("config_log_file: Unable to alloc mem!");
2238 return CMD_WARNING_CONFIG_FAILED
;
2241 if ((p
= XMALLOC(MTYPE_TMP
, strlen(cwd
) + strlen(fname
) + 2))
2243 zlog_err("config_log_file: Unable to alloc mem!");
2244 return CMD_WARNING_CONFIG_FAILED
;
2246 sprintf(p
, "%s/%s", cwd
, fname
);
2251 ret
= zlog_set_file(fullpath
, loglevel
);
2254 XFREE(MTYPE_TMP
, p
);
2257 vty_out(vty
, "can't open logfile %s\n", fname
);
2258 return CMD_WARNING_CONFIG_FAILED
;
2262 XFREE(MTYPE_HOST
, host
.logfile
);
2264 host
.logfile
= XSTRDUP(MTYPE_HOST
, fname
);
2266 #if defined(HAVE_CUMULUS)
2267 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2268 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2273 DEFUN (config_log_file
,
2274 config_log_file_cmd
,
2275 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2278 "Logging filename\n"
2281 int idx_filename
= 2;
2282 int idx_log_levels
= 3;
2285 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2287 return CMD_ERR_NO_MATCH
;
2288 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2290 return set_log_file(vty
, argv
[idx_filename
]->arg
,
2291 zlog_default
->default_lvl
);
2294 DEFUN (no_config_log_file
,
2295 no_config_log_file_cmd
,
2296 "no log file [FILENAME [LEVEL]]",
2299 "Cancel logging to file\n"
2300 "Logging file name\n"
2306 XFREE(MTYPE_HOST
, host
.logfile
);
2308 host
.logfile
= NULL
;
2313 DEFUN (config_log_syslog
,
2314 config_log_syslog_cmd
,
2315 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2317 "Set syslog logging level\n"
2320 int idx_log_levels
= 2;
2323 if ((level
= level_match(argv
[idx_log_levels
]->arg
))
2325 return CMD_ERR_NO_MATCH
;
2326 zlog_set_level(ZLOG_DEST_SYSLOG
, level
);
2329 zlog_set_level(ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2334 DEFUN (no_config_log_syslog
,
2335 no_config_log_syslog_cmd
,
2336 "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>]",
2339 "Cancel logging to syslog\n"
2343 zlog_set_level(ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2347 DEFUN (config_log_facility
,
2348 config_log_facility_cmd
,
2349 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2351 "Facility parameter for syslog messages\n"
2355 int facility
= facility_match(argv
[idx_target
]->arg
);
2357 zlog_default
->facility
= facility
;
2361 DEFUN (no_config_log_facility
,
2362 no_config_log_facility_cmd
,
2363 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2366 "Reset syslog facility to default (daemon)\n"
2369 zlog_default
->facility
= LOG_DAEMON
;
2374 config_log_trap
, config_log_trap_cmd
,
2375 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2377 "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC
)
2382 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2383 return CMD_ERR_NO_MATCH
;
2385 zlog_default
->default_lvl
= new_level
;
2386 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2387 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2388 zlog_default
->maxlvl
[i
] = new_level
;
2393 no_config_log_trap
, no_config_log_trap_cmd
,
2394 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2397 "Permit all logging information\n" LOG_LEVEL_DESC
)
2399 zlog_default
->default_lvl
= LOG_DEBUG
;
2403 DEFUN (config_log_record_priority
,
2404 config_log_record_priority_cmd
,
2405 "log record-priority",
2407 "Log the priority of the message within the message\n")
2409 zlog_default
->record_priority
= 1;
2413 DEFUN (no_config_log_record_priority
,
2414 no_config_log_record_priority_cmd
,
2415 "no log record-priority",
2418 "Do not log the priority of the message within the message\n")
2420 zlog_default
->record_priority
= 0;
2424 DEFUN (config_log_timestamp_precision
,
2425 config_log_timestamp_precision_cmd
,
2426 "log timestamp precision (0-6)",
2428 "Timestamp configuration\n"
2429 "Set the timestamp precision\n"
2430 "Number of subsecond digits\n")
2433 zlog_default
->timestamp_precision
=
2434 strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2438 DEFUN (no_config_log_timestamp_precision
,
2439 no_config_log_timestamp_precision_cmd
,
2440 "no log timestamp precision",
2443 "Timestamp configuration\n"
2444 "Reset the timestamp precision to the default value of 0\n")
2446 zlog_default
->timestamp_precision
= 0;
2450 DEFUN (debug_memstats
,
2452 "[no] debug memstats-at-exit",
2455 "Print memory type statistics at exit\n")
2457 debug_memstats_at_exit
= !!strcmp(argv
[0]->text
, "no");
2461 int cmd_banner_motd_file(const char *file
)
2463 int success
= CMD_SUCCESS
;
2468 rpath
= realpath(file
, p
);
2470 return CMD_ERR_NO_FILE
;
2471 in
= strstr(rpath
, SYSCONFDIR
);
2474 XFREE(MTYPE_HOST
, host
.motdfile
);
2475 host
.motdfile
= XSTRDUP(MTYPE_HOST
, file
);
2477 success
= CMD_WARNING_CONFIG_FAILED
;
2482 DEFUN (banner_motd_file
,
2483 banner_motd_file_cmd
,
2484 "banner motd file FILE",
2487 "Banner from a file\n"
2491 const char *filename
= argv
[idx_file
]->arg
;
2492 int cmd
= cmd_banner_motd_file(filename
);
2494 if (cmd
== CMD_ERR_NO_FILE
)
2495 vty_out(vty
, "%s does not exist", filename
);
2496 else if (cmd
== CMD_WARNING_CONFIG_FAILED
)
2497 vty_out(vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2502 DEFUN (banner_motd_default
,
2503 banner_motd_default_cmd
,
2504 "banner motd default",
2505 "Set banner string\n"
2506 "Strings for motd\n"
2509 host
.motd
= default_motd
;
2513 DEFUN (no_banner_motd
,
2517 "Set banner string\n"
2518 "Strings for motd\n")
2522 XFREE(MTYPE_HOST
, host
.motdfile
);
2523 host
.motdfile
= NULL
;
2530 "Find CLI command containing text\n"
2531 "Text to search for\n")
2533 char *text
= argv_concat(argv
, argc
, 1);
2534 const struct cmd_node
*node
;
2535 const struct cmd_element
*cli
;
2538 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++) {
2539 node
= vector_slot(cmdvec
, i
);
2542 clis
= node
->cmd_vector
;
2543 for (unsigned int j
= 0; j
< vector_active(clis
); j
++) {
2544 cli
= vector_slot(clis
, j
);
2545 if (strcasestr(cli
->string
, text
))
2546 vty_out(vty
, " (%s) %s\n",
2547 node_names
[node
->node
], cli
->string
);
2551 XFREE(MTYPE_TMP
, text
);
2556 /* Set config filename. Called from vty.c */
2557 void host_config_set(const char *filename
)
2560 XFREE(MTYPE_HOST
, host
.config
);
2561 host
.config
= XSTRDUP(MTYPE_HOST
, filename
);
2564 const char *host_config_get(void)
2569 void install_default(enum node_type node
)
2571 install_element(node
, &config_exit_cmd
);
2572 install_element(node
, &config_quit_cmd
);
2573 install_element(node
, &config_end_cmd
);
2574 install_element(node
, &config_help_cmd
);
2575 install_element(node
, &config_list_cmd
);
2576 install_element(node
, &find_cmd
);
2578 install_element(node
, &config_write_cmd
);
2579 install_element(node
, &show_running_config_cmd
);
2581 install_element(node
, &autocomplete_cmd
);
2584 /* Initialize command interface. Install basic nodes and commands.
2586 * terminal = 0 -- vtysh / no logging, no config control
2587 * terminal = 1 -- normal daemon
2588 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2589 void cmd_init(int terminal
)
2591 struct utsname names
;
2593 if (array_size(node_names
) != NODE_TYPE_MAX
)
2594 assert(!"Update the CLI node description array!");
2599 varhandlers
= list_new();
2601 /* Allocate initial top vector of commands. */
2602 cmdvec
= vector_init(VECTOR_MIN_SIZE
);
2604 /* Default host value settings. */
2605 host
.name
= XSTRDUP(MTYPE_HOST
, names
.nodename
);
2606 #ifdef HAVE_STRUCT_UTSNAME_DOMAINNAME
2607 if ((strcmp(names
.domainname
, "(none)") == 0))
2608 host
.domainname
= NULL
;
2610 host
.domainname
= XSTRDUP(MTYPE_HOST
, names
.domainname
);
2612 host
.domainname
= NULL
;
2614 host
.password
= NULL
;
2616 host
.logfile
= NULL
;
2618 host
.noconfig
= (terminal
< 0);
2620 host
.motd
= default_motd
;
2621 host
.motdfile
= NULL
;
2623 /* Install top nodes. */
2624 install_node(&view_node
, NULL
);
2625 install_node(&enable_node
, NULL
);
2626 install_node(&auth_node
, NULL
);
2627 install_node(&auth_enable_node
, NULL
);
2628 install_node(&config_node
, config_write_host
);
2630 /* Each node's basic commands. */
2631 install_element(VIEW_NODE
, &show_version_cmd
);
2632 install_element(ENABLE_NODE
, &show_startup_config_cmd
);
2633 install_element(ENABLE_NODE
, &debug_memstats_cmd
);
2636 install_element(VIEW_NODE
, &config_list_cmd
);
2637 install_element(VIEW_NODE
, &config_exit_cmd
);
2638 install_element(VIEW_NODE
, &config_quit_cmd
);
2639 install_element(VIEW_NODE
, &config_help_cmd
);
2640 install_element(VIEW_NODE
, &config_enable_cmd
);
2641 install_element(VIEW_NODE
, &config_terminal_length_cmd
);
2642 install_element(VIEW_NODE
, &config_terminal_no_length_cmd
);
2643 install_element(VIEW_NODE
, &show_logging_cmd
);
2644 install_element(VIEW_NODE
, &show_commandtree_cmd
);
2645 install_element(VIEW_NODE
, &echo_cmd
);
2646 install_element(VIEW_NODE
, &autocomplete_cmd
);
2647 install_element(VIEW_NODE
, &find_cmd
);
2649 install_element(ENABLE_NODE
, &config_end_cmd
);
2650 install_element(ENABLE_NODE
, &config_disable_cmd
);
2651 install_element(ENABLE_NODE
, &config_terminal_cmd
);
2652 install_element(ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2653 install_element(ENABLE_NODE
, &config_write_cmd
);
2654 install_element(ENABLE_NODE
, &show_running_config_cmd
);
2655 install_element(ENABLE_NODE
, &config_logmsg_cmd
);
2657 install_default(CONFIG_NODE
);
2660 workqueue_cmd_init();
2664 install_element(CONFIG_NODE
, &hostname_cmd
);
2665 install_element(CONFIG_NODE
, &no_hostname_cmd
);
2666 install_element(CONFIG_NODE
, &domainname_cmd
);
2667 install_element(CONFIG_NODE
, &no_domainname_cmd
);
2668 install_element(CONFIG_NODE
, &frr_version_defaults_cmd
);
2669 install_element(CONFIG_NODE
, &debug_memstats_cmd
);
2672 install_element(CONFIG_NODE
, &password_cmd
);
2673 install_element(CONFIG_NODE
, &enable_password_cmd
);
2674 install_element(CONFIG_NODE
, &no_enable_password_cmd
);
2676 install_element(CONFIG_NODE
, &config_log_stdout_cmd
);
2677 install_element(CONFIG_NODE
, &no_config_log_stdout_cmd
);
2678 install_element(CONFIG_NODE
, &config_log_monitor_cmd
);
2679 install_element(CONFIG_NODE
, &no_config_log_monitor_cmd
);
2680 install_element(CONFIG_NODE
, &config_log_file_cmd
);
2681 install_element(CONFIG_NODE
, &no_config_log_file_cmd
);
2682 install_element(CONFIG_NODE
, &config_log_syslog_cmd
);
2683 install_element(CONFIG_NODE
, &no_config_log_syslog_cmd
);
2684 install_element(CONFIG_NODE
, &config_log_facility_cmd
);
2685 install_element(CONFIG_NODE
, &no_config_log_facility_cmd
);
2686 install_element(CONFIG_NODE
, &config_log_trap_cmd
);
2687 install_element(CONFIG_NODE
, &no_config_log_trap_cmd
);
2688 install_element(CONFIG_NODE
, &config_log_record_priority_cmd
);
2689 install_element(CONFIG_NODE
,
2690 &no_config_log_record_priority_cmd
);
2691 install_element(CONFIG_NODE
,
2692 &config_log_timestamp_precision_cmd
);
2693 install_element(CONFIG_NODE
,
2694 &no_config_log_timestamp_precision_cmd
);
2695 install_element(CONFIG_NODE
, &service_password_encrypt_cmd
);
2696 install_element(CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2697 install_element(CONFIG_NODE
, &banner_motd_default_cmd
);
2698 install_element(CONFIG_NODE
, &banner_motd_file_cmd
);
2699 install_element(CONFIG_NODE
, &no_banner_motd_cmd
);
2700 install_element(CONFIG_NODE
, &service_terminal_length_cmd
);
2701 install_element(CONFIG_NODE
, &no_service_terminal_length_cmd
);
2703 vrf_install_commands();
2707 grammar_sandbox_init();
2711 void cmd_terminate()
2713 struct cmd_node
*cmd_node
;
2716 for (unsigned int i
= 0; i
< vector_active(cmdvec
); i
++)
2717 if ((cmd_node
= vector_slot(cmdvec
, i
)) != NULL
) {
2718 // deleting the graph delets the cmd_element as
2720 graph_delete_graph(cmd_node
->cmdgraph
);
2721 vector_free(cmd_node
->cmd_vector
);
2722 hash_clean(cmd_node
->cmd_hash
, NULL
);
2723 hash_free(cmd_node
->cmd_hash
);
2724 cmd_node
->cmd_hash
= NULL
;
2727 vector_free(cmdvec
);
2732 XFREE(MTYPE_HOST
, host
.name
);
2733 if (host
.domainname
)
2734 XFREE(MTYPE_HOST
, host
.domainname
);
2736 XFREE(MTYPE_HOST
, host
.password
);
2737 if (host
.password_encrypt
)
2738 XFREE(MTYPE_HOST
, host
.password_encrypt
);
2740 XFREE(MTYPE_HOST
, host
.enable
);
2741 if (host
.enable_encrypt
)
2742 XFREE(MTYPE_HOST
, host
.enable_encrypt
);
2744 XFREE(MTYPE_HOST
, host
.logfile
);
2746 XFREE(MTYPE_HOST
, host
.motdfile
);
2748 XFREE(MTYPE_HOST
, host
.config
);
2750 list_delete_and_null(&varhandlers
);