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 /* Command vector which includes some level of command lists. Normally
51 each daemon maintains each own cmdvec. */
54 /* Host information structure. */
57 /* Standard command node structures. */
58 static struct cmd_node auth_node
=
64 static struct cmd_node view_node
=
70 static struct cmd_node auth_enable_node
=
76 static struct cmd_node enable_node
=
82 static struct cmd_node config_node
=
89 /* Default motd string. */
90 static const char *default_motd
= FRR_DEFAULT_MOTD
;
92 static const struct facility_map
{
96 } syslog_facilities
[] =
98 { LOG_KERN
, "kern", 1 },
99 { LOG_USER
, "user", 2 },
100 { LOG_MAIL
, "mail", 1 },
101 { LOG_DAEMON
, "daemon", 1 },
102 { LOG_AUTH
, "auth", 1 },
103 { LOG_SYSLOG
, "syslog", 1 },
104 { LOG_LPR
, "lpr", 2 },
105 { LOG_NEWS
, "news", 1 },
106 { LOG_UUCP
, "uucp", 2 },
107 { LOG_CRON
, "cron", 1 },
109 { LOG_FTP
, "ftp", 1 },
111 { LOG_LOCAL0
, "local0", 6 },
112 { LOG_LOCAL1
, "local1", 6 },
113 { LOG_LOCAL2
, "local2", 6 },
114 { LOG_LOCAL3
, "local3", 6 },
115 { LOG_LOCAL4
, "local4", 6 },
116 { LOG_LOCAL5
, "local5", 6 },
117 { LOG_LOCAL6
, "local6", 6 },
118 { LOG_LOCAL7
, "local7", 6 },
123 facility_name(int facility
)
125 const struct facility_map
*fm
;
127 for (fm
= syslog_facilities
; fm
->name
; fm
++)
128 if (fm
->facility
== facility
)
134 facility_match(const char *str
)
136 const struct facility_map
*fm
;
138 for (fm
= syslog_facilities
; fm
->name
; fm
++)
139 if (!strncmp(str
,fm
->name
,fm
->match
))
145 level_match(const char *s
)
149 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
150 if (!strncmp (s
, zlog_priority
[level
], 2))
152 return ZLOG_DISABLED
;
155 /* This is called from main when a daemon is invoked with -v or --version. */
157 print_version (const char *progname
)
159 printf ("%s version %s\n", progname
, FRR_VERSION
);
160 printf ("%s\n", FRR_COPYRIGHT
);
161 printf ("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
165 /* Utility function to concatenate argv argument into a single string
166 with inserting ' ' character between each argument. */
168 argv_concat (struct cmd_token
**argv
, int argc
, int shift
)
176 for (i
= shift
; i
< argc
; i
++)
177 len
+= strlen(argv
[i
]->arg
)+1;
180 p
= str
= XMALLOC(MTYPE_TMP
, len
);
181 for (i
= shift
; i
< argc
; i
++)
184 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
193 * Convenience function for accessing argv data.
197 * @param text definition snippet of the desired token
198 * @param index the starting index, and where to store the
199 * index of the found token if it exists
200 * @return 1 if found, 0 otherwise
203 argv_find (struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
206 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
207 if ((found
= strmatch (text
, argv
[i
]->text
)))
213 cmd_hash_key (void *p
)
215 return (uintptr_t) p
;
219 cmd_hash_cmp (const void *a
, const void *b
)
224 /* Install top node of command vector. */
226 install_node (struct cmd_node
*node
,
227 int (*func
) (struct vty
*))
229 vector_set_index (cmdvec
, node
->node
, node
);
231 node
->cmdgraph
= graph_new ();
232 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
234 struct cmd_token
*token
= cmd_token_new (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
235 graph_new_node (node
->cmdgraph
, token
, (void (*)(void *)) &cmd_token_del
);
236 node
->cmd_hash
= hash_create (cmd_hash_key
, cmd_hash_cmp
, NULL
);
240 * Tokenizes a string, storing tokens in a vector.
241 * Whitespace is ignored.
243 * Delimiter string = " \n\r\t".
245 * @param string to tokenize
246 * @return tokenized string
249 cmd_make_strvec (const char *string
)
251 if (!string
) return NULL
;
253 char *copy
, *copystart
;
254 copystart
= copy
= XSTRDUP (MTYPE_TMP
, string
);
256 // skip leading whitespace
257 while (isspace ((int) *copy
) && *copy
!= '\0') copy
++;
259 // if the entire string was whitespace or a comment, return
260 if (*copy
== '\0' || *copy
== '!' || *copy
== '#')
262 XFREE (MTYPE_TMP
, copystart
);
266 vector strvec
= vector_init (VECTOR_MIN_SIZE
);
267 const char *delim
= " \n\r\t", *tok
= NULL
;
270 tok
= strsep (©
, delim
);
272 vector_set (strvec
, XSTRDUP (MTYPE_STRVEC
, tok
));
275 XFREE (MTYPE_TMP
, copystart
);
279 /* Free allocated string vector. */
281 cmd_free_strvec (vector v
)
289 for (i
= 0; i
< vector_active (v
); i
++)
290 if ((cp
= vector_slot (v
, i
)) != NULL
)
291 XFREE (MTYPE_STRVEC
, cp
);
296 /* Return prompt character of specified node. */
298 cmd_prompt (enum node_type node
)
300 struct cmd_node
*cnode
;
302 cnode
= vector_slot (cmdvec
, node
);
303 return cnode
->prompt
;
306 /* Install a command into a node. */
308 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
310 struct cmd_node
*cnode
;
312 /* cmd_init hasn't been called */
315 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
320 cnode
= vector_slot (cmdvec
, ntype
);
324 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
326 fprintf (stderr
, "Have you called install_node before this install_element?\n");
330 if (hash_lookup (cnode
->cmd_hash
, cmd
) != NULL
)
333 "Multiple command installs to node %d of command:\n%s\n",
338 assert (hash_get (cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
340 struct graph
*graph
= graph_new();
341 struct cmd_token
*token
= cmd_token_new (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
342 graph_new_node (graph
, token
, (void (*)(void *)) &cmd_token_del
);
344 cmd_graph_parse (graph
, cmd
);
345 cmd_graph_names (graph
);
346 cmd_graph_merge (cnode
->cmdgraph
, graph
, +1);
347 graph_delete_graph (graph
);
349 vector_set (cnode
->cmd_vector
, cmd
);
351 if (ntype
== VIEW_NODE
)
352 install_element (ENABLE_NODE
, cmd
);
356 uninstall_element (enum node_type ntype
, struct cmd_element
*cmd
)
358 struct cmd_node
*cnode
;
360 /* cmd_init hasn't been called */
363 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
368 cnode
= vector_slot (cmdvec
, ntype
);
372 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
374 fprintf (stderr
, "Have you called install_node before this install_element?\n");
378 if (hash_release (cnode
->cmd_hash
, cmd
) == NULL
)
381 "Trying to uninstall non-installed command (node %d):\n%s\n",
386 vector_unset_value (cnode
->cmd_vector
, cmd
);
388 struct graph
*graph
= graph_new();
389 struct cmd_token
*token
= cmd_token_new (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
390 graph_new_node (graph
, token
, (void (*)(void *)) &cmd_token_del
);
392 cmd_graph_parse (graph
, cmd
);
393 cmd_graph_names (graph
);
394 cmd_graph_merge (cnode
->cmdgraph
, graph
, -1);
395 graph_delete_graph (graph
);
397 if (ntype
== VIEW_NODE
)
398 uninstall_element (ENABLE_NODE
, cmd
);
402 static const unsigned char itoa64
[] =
403 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
406 to64(char *s
, long v
, int n
)
410 *s
++ = itoa64
[v
&0x3f];
416 zencrypt (const char *passwd
)
420 char *crypt (const char *, const char *);
424 to64(&salt
[0], random(), 3);
425 to64(&salt
[3], tv
.tv_usec
, 3);
428 return crypt (passwd
, salt
);
431 /* This function write configuration of this host. */
433 config_write_host (struct vty
*vty
)
436 vty_outln (vty
, "hostname %s", host
.name
);
440 if (host
.password_encrypt
)
441 vty_outln (vty
, "password 8 %s", host
.password_encrypt
);
442 if (host
.enable_encrypt
)
443 vty_outln (vty
, "enable password 8 %s", host
.enable_encrypt
);
448 vty_outln (vty
, "password %s", host
.password
);
450 vty_outln (vty
, "enable password %s", host
.enable
);
453 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
455 vty_outln (vty
,"! N.B. The 'log trap' command is deprecated.");
456 vty_outln (vty
, "log trap %s",
457 zlog_priority
[zlog_default
->default_lvl
]);
460 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
462 vty_out (vty
, "log file %s", host
.logfile
);
463 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
465 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
466 vty_out (vty
, VTYNL
);
469 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
471 vty_out (vty
, "log stdout");
472 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
474 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
475 vty_out (vty
, VTYNL
);
478 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
479 vty_outln (vty
,"no log monitor");
480 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
481 vty_outln (vty
,"log monitor %s",
482 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]]);
484 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
486 vty_out (vty
, "log syslog");
487 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
489 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
490 vty_out (vty
, VTYNL
);
493 if (zlog_default
->facility
!= LOG_DAEMON
)
494 vty_outln (vty
, "log facility %s",
495 facility_name(zlog_default
->facility
));
497 if (zlog_default
->record_priority
== 1)
498 vty_outln (vty
, "log record-priority");
500 if (zlog_default
->timestamp_precision
> 0)
501 vty_outln (vty
, "log timestamp precision %d",
502 zlog_default
->timestamp_precision
);
505 vty_outln (vty
, "service advanced-vty");
508 vty_outln (vty
, "service password-encryption");
511 vty_outln (vty
, "service terminal-length %d",host
.lines
);
514 vty_outln (vty
, "banner motd file %s", host
.motdfile
);
515 else if (! host
.motd
)
516 vty_outln (vty
, "no banner motd");
521 /* Utility function for getting command graph. */
522 static struct graph
*
523 cmd_node_graph (vector v
, enum node_type ntype
)
525 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
526 return cnode
->cmdgraph
;
530 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
531 if ( first_word
!= NULL
&&
534 node
!= AUTH_ENABLE_NODE
&&
535 0 == strcmp( "do", first_word
) )
541 * Compare function for cmd_token.
542 * Used with qsort to sort command completions.
545 compare_completions (const void *fst
, const void *snd
)
547 struct cmd_token
*first
= *(struct cmd_token
**) fst
,
548 *secnd
= *(struct cmd_token
**) snd
;
549 return strcmp (first
->text
, secnd
->text
);
553 * Takes a list of completions returned by command_complete,
554 * dedeuplicates them based on both text and description,
555 * sorts them, and returns them as a vector.
557 * @param completions linked list of cmd_token
558 * @return deduplicated and sorted vector with
561 completions_to_vec (struct list
*completions
)
563 vector comps
= vector_init (VECTOR_MIN_SIZE
);
566 struct cmd_token
*token
, *cr
= NULL
;
567 unsigned int i
, exists
;
568 for (ALL_LIST_ELEMENTS_RO(completions
,ln
,token
))
570 if (token
->type
== END_TKN
&& (cr
= token
))
573 // linear search for token in completions vector
575 for (i
= 0; i
< vector_active (comps
) && !exists
; i
++)
577 struct cmd_token
*curr
= vector_slot (comps
, i
);
579 exists
= !strcmp (curr
->text
, token
->text
) &&
580 !strcmp (curr
->desc
, token
->desc
);
582 exists
= !strcmp (curr
->text
, token
->text
);
583 #endif /* VTYSH_DEBUG */
587 vector_set (comps
, token
);
592 vector_active (comps
),
594 &compare_completions
);
596 // make <cr> the first element, if it is present
599 vector_set_index (comps
, vector_active (comps
), NULL
);
600 memmove (comps
->index
+ 1, comps
->index
, (comps
->alloced
- 1) * sizeof (void *));
601 vector_set_index (comps
, 0, cr
);
607 * Generates a vector of cmd_token representing possible completions
608 * on the current input.
610 * @param vline the vectorized input line
611 * @param vty the vty with the node to match on
612 * @param status pointer to matcher status code
613 * @return vector of struct cmd_token * with possible completions
616 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
)
618 struct list
*completions
;
619 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
621 enum matcher_rv rv
= command_complete (cmdgraph
, vline
, &completions
);
623 if (MATCHER_ERROR(rv
))
625 *status
= CMD_ERR_NO_MATCH
;
629 vector comps
= completions_to_vec (completions
);
630 list_delete (completions
);
632 // set status code appropriately
633 switch (vector_active (comps
))
636 *status
= CMD_ERR_NO_MATCH
;
639 *status
= CMD_COMPLETE_FULL_MATCH
;
642 *status
= CMD_COMPLETE_LIST_MATCH
;
649 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
653 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
655 enum node_type onode
;
656 vector shifted_vline
;
660 vty
->node
= ENABLE_NODE
;
661 /* We can try it on enable node, cos' the vty is authenticated */
663 shifted_vline
= vector_init (vector_count(vline
));
665 for (index
= 1; index
< vector_active (vline
); index
++)
667 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
670 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
);
672 vector_free(shifted_vline
);
677 return cmd_complete_command_real (vline
, vty
, status
);
680 static struct list
*varhandlers
= NULL
;
683 cmd_variable_complete (struct cmd_token
*token
, const char *arg
, vector comps
)
686 const struct cmd_variable_handler
*cvh
;
690 tmpcomps
= arg
? vector_init (VECTOR_MIN_SIZE
) : comps
;
692 for (ALL_LIST_ELEMENTS_RO(varhandlers
, ln
, cvh
))
694 if (cvh
->tokenname
&& strcmp(cvh
->tokenname
, token
->text
))
696 if (cvh
->varname
&& (!token
->varname
|| strcmp(cvh
->varname
, token
->varname
)))
698 cvh
->completions(tmpcomps
, token
);
706 for (i
= vector_active(tmpcomps
); i
; i
--)
708 char *item
= vector_slot(tmpcomps
, i
- 1);
709 if (strlen(item
) >= argsz
710 && !strncmp(item
, arg
, argsz
))
711 vector_set(comps
, item
);
713 XFREE(MTYPE_COMPLETION
, item
);
715 vector_free(tmpcomps
);
718 #define AUTOCOMP_INDENT 5
721 cmd_variable_comp2str(vector comps
, unsigned short cols
, const char nl
[])
724 char *buf
= XCALLOC(MTYPE_TMP
, bsz
);
725 int lc
= AUTOCOMP_INDENT
;
726 size_t cs
= AUTOCOMP_INDENT
;
727 size_t nllen
= strlen(nl
);
729 snprintf(buf
, bsz
, "%*s", AUTOCOMP_INDENT
, "");
730 for (size_t j
= 0; j
< vector_active (comps
); j
++)
732 char *item
= vector_slot (comps
, j
);
733 itemlen
= strlen(item
);
735 if (cs
+ itemlen
+ nllen
+ AUTOCOMP_INDENT
+ 2 >= bsz
)
736 buf
= XREALLOC(MTYPE_TMP
, buf
, (bsz
*= 2));
738 if (lc
+ itemlen
+ 1 >= cols
)
740 cs
+= snprintf(&buf
[cs
], bsz
- cs
, "%s%*s", nl
, AUTOCOMP_INDENT
, "");
741 lc
= AUTOCOMP_INDENT
;
744 size_t written
= snprintf(&buf
[cs
], bsz
- cs
, "%s ", item
);
747 XFREE (MTYPE_COMPLETION
, item
);
748 vector_set_index (comps
, j
, NULL
);
754 cmd_variable_handler_register (const struct cmd_variable_handler
*cvh
)
759 for (; cvh
->completions
; cvh
++)
760 listnode_add(varhandlers
, (void *)cvh
);
763 DEFUN_HIDDEN (autocomplete
,
765 "autocomplete TYPE TEXT VARNAME",
766 "Autocompletion handler (internal, for vtysh)\n"
769 "cmd_token->varname\n")
771 struct cmd_token tok
;
772 vector comps
= vector_init(32);
775 memset(&tok
, 0, sizeof(tok
));
776 tok
.type
= atoi(argv
[1]->arg
);
777 tok
.text
= argv
[2]->arg
;
778 tok
.varname
= argv
[3]->arg
;
779 if (!strcmp(tok
.varname
, "-"))
782 cmd_variable_complete(&tok
, NULL
, comps
);
784 for (i
= 0; i
< vector_active(comps
); i
++)
786 char *text
= vector_slot(comps
, i
);
787 vty_out(vty
, "%s\n", text
);
788 XFREE(MTYPE_COMPLETION
, text
);
796 * Generate possible tab-completions for the given input. This function only
797 * returns results that would result in a valid command if used as Readline
798 * completions (as is the case in vtysh). For instance, if the passed vline ends
799 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
801 * @param vline vectorized input line
803 * @param status location to store matcher status code in
804 * @return set of valid strings for use with Readline as tab-completions.
808 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
811 int original_node
= vty
->node
;
812 vector input_line
= vector_init (vector_count (vline
));
814 // if the first token is 'do' we'll want to execute the command in the enable node
815 int do_shortcut
= cmd_try_do_shortcut (vty
->node
, vector_slot (vline
, 0));
816 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
818 // construct the input line we'll be matching on
819 unsigned int offset
= (do_shortcut
) ? 1 : 0;
820 for (unsigned index
= 0; index
+ offset
< vector_active (vline
); index
++)
821 vector_set_index (input_line
, index
, vector_lookup (vline
, index
+ offset
));
823 // get token completions -- this is a copying operation
824 vector comps
= NULL
, initial_comps
;
825 initial_comps
= cmd_complete_command_real (input_line
, vty
, status
);
827 if (!MATCHER_ERROR (*status
))
829 assert (initial_comps
);
830 // filter out everything that is not suitable for a tab-completion
831 comps
= vector_init (VECTOR_MIN_SIZE
);
832 for (unsigned int i
= 0; i
< vector_active(initial_comps
); i
++)
834 struct cmd_token
*token
= vector_slot (initial_comps
, i
);
835 if (token
->type
== WORD_TKN
)
836 vector_set (comps
, XSTRDUP (MTYPE_COMPLETION
, token
->text
));
837 else if (IS_VARYING_TOKEN(token
->type
))
839 const char *ref
= vector_lookup(vline
, vector_active (vline
) - 1);
840 cmd_variable_complete (token
, ref
, comps
);
843 vector_free (initial_comps
);
845 // since we filtered results, we need to re-set status code
846 switch (vector_active (comps
))
849 *status
= CMD_ERR_NO_MATCH
;
852 *status
= CMD_COMPLETE_FULL_MATCH
;
855 *status
= CMD_COMPLETE_LIST_MATCH
;
858 // copy completions text into an array of char*
859 ret
= XMALLOC (MTYPE_TMP
, (vector_active (comps
)+1) * sizeof (char *));
861 for (i
= 0; i
< vector_active (comps
); i
++)
863 ret
[i
] = vector_slot (comps
, i
);
865 // set the last element to NULL, because this array is used in
866 // a Readline completion_generator function which expects NULL
867 // as a sentinel value
872 else if (initial_comps
)
873 vector_free (initial_comps
);
875 // comps should always be null here
878 // free the adjusted input line
879 vector_free (input_line
);
881 // reset vty->node to its original value
882 vty
->node
= original_node
;
887 /* return parent node */
888 /* MUST eventually converge on CONFIG_NODE */
890 node_parent ( enum node_type node
)
894 assert (node
> CONFIG_NODE
);
900 case BGP_VRF_POLICY_NODE
:
901 case BGP_VNC_DEFAULTS_NODE
:
902 case BGP_VNC_NVE_GROUP_NODE
:
903 case BGP_VNC_L2_GROUP_NODE
:
913 case BGP_EVPN_VNI_NODE
:
916 case KEYCHAIN_KEY_NODE
:
919 case LINK_PARAMS_NODE
:
920 ret
= INTERFACE_NODE
;
926 case LDP_IPV4_IFACE_NODE
:
929 case LDP_IPV6_IFACE_NODE
:
932 case LDP_PSEUDOWIRE_NODE
:
933 ret
= LDP_L2VPN_NODE
;
943 /* Execute command by argument vline vector. */
945 cmd_execute_command_real (vector vline
,
946 enum filter_type filter
,
948 const struct cmd_element
**cmd
)
950 struct list
*argv_list
;
951 enum matcher_rv status
;
952 const struct cmd_element
*matched_element
= NULL
;
954 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
955 status
= command_match (cmdgraph
, vline
, &argv_list
, &matched_element
);
958 *cmd
= matched_element
;
960 // if matcher error, return corresponding CMD_ERR
961 if (MATCHER_ERROR(status
))
964 list_delete (argv_list
);
967 case MATCHER_INCOMPLETE
:
968 return CMD_ERR_INCOMPLETE
;
969 case MATCHER_AMBIGUOUS
:
970 return CMD_ERR_AMBIGUOUS
;
972 return CMD_ERR_NO_MATCH
;
976 // build argv array from argv list
977 struct cmd_token
**argv
= XMALLOC (MTYPE_TMP
, argv_list
->count
* sizeof (struct cmd_token
*));
979 struct cmd_token
*token
;
981 for (ALL_LIST_ELEMENTS_RO(argv_list
,ln
,token
))
984 int argc
= argv_list
->count
;
987 if (matched_element
->daemon
)
988 ret
= CMD_SUCCESS_DAEMON
;
990 ret
= matched_element
->func (matched_element
, vty
, argc
, argv
);
992 // delete list and cmd_token's in it
993 list_delete (argv_list
);
994 XFREE (MTYPE_TMP
, argv
);
1000 * Execute a given command, handling things like "do ..." and checking
1001 * whether the given command might apply at a parent node if doesn't
1002 * apply for the current node.
1004 * @param vline Command line input, vector of char* where each element is
1006 * @param vty The vty context in which the command should be executed.
1007 * @param cmd Pointer where the struct cmd_element of the matched command
1008 * will be stored, if any. May be set to NULL if this info is
1010 * @param vtysh If set != 0, don't lookup the command at parent nodes.
1011 * @return The status of the command that has been executed or an error code
1012 * as to why no command could be executed.
1015 cmd_execute_command (vector vline
, struct vty
*vty
,
1016 const struct cmd_element
**cmd
,
1019 int ret
, saved_ret
= 0;
1020 enum node_type onode
, try_node
;
1022 onode
= try_node
= vty
->node
;
1024 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0)))
1026 vector shifted_vline
;
1029 vty
->node
= ENABLE_NODE
;
1030 /* We can try it on enable node, cos' the vty is authenticated */
1032 shifted_vline
= vector_init (vector_count(vline
));
1034 for (index
= 1; index
< vector_active (vline
); index
++)
1035 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
1037 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
1039 vector_free(shifted_vline
);
1044 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
1049 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1051 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
1052 while (vty
->node
> CONFIG_NODE
)
1054 try_node
= node_parent(try_node
);
1055 vty
->node
= try_node
;
1056 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
1057 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
1060 /* no command succeeded, reset the vty to the original node */
1064 /* return command status for original node */
1069 * Execute a given command, matching it strictly against the current node.
1070 * This mode is used when reading config files.
1072 * @param vline Command line input, vector of char* where each element is
1074 * @param vty The vty context in which the command should be executed.
1075 * @param cmd Pointer where the struct cmd_element* of the matched command
1076 * will be stored, if any. May be set to NULL if this info is
1078 * @return The status of the command that has been executed or an error code
1079 * as to why no command could be executed.
1082 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
1083 const struct cmd_element
**cmd
)
1085 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
1089 * Parse one line of config, walking up the parse tree attempting to find a match
1091 * @param vty The vty context in which the command should be executed.
1092 * @param cmd Pointer where the struct cmd_element* of the match command
1093 * will be stored, if any. May be set to NULL if this info is
1095 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
1097 * @return The status of the command that has been executed or an error code
1098 * as to why no command could be executed.
1101 command_config_read_one_line (struct vty
*vty
, const struct cmd_element
**cmd
, int use_daemon
)
1107 vline
= cmd_make_strvec (vty
->buf
);
1109 /* In case of comment line */
1113 /* Execute configuration command : this is strict match */
1114 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
1116 // Climb the tree and try the command again at each node
1117 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1118 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1119 ret
!= CMD_SUCCESS
&&
1120 ret
!= CMD_WARNING
&&
1121 vty
->node
!= CONFIG_NODE
) {
1123 saved_node
= vty
->node
;
1125 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1126 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1127 ret
!= CMD_SUCCESS
&&
1128 ret
!= CMD_WARNING
&&
1129 vty
->node
> CONFIG_NODE
) {
1130 vty
->node
= node_parent(vty
->node
);
1131 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
1134 // If climbing the tree did not work then ignore the command and
1135 // stay at the same node
1136 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
1137 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
1138 ret
!= CMD_SUCCESS
&&
1141 vty
->node
= saved_node
;
1145 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
1146 memcpy (vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
1148 cmd_free_strvec (vline
);
1153 /* Configuration make from file. */
1155 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
1157 int ret
, error_ret
=0;
1160 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
1165 ret
= command_config_read_one_line (vty
, NULL
, 0);
1167 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
1168 ret
!= CMD_ERR_NOTHING_TODO
)
1179 /* Configuration from terminal */
1180 DEFUN (config_terminal
,
1181 config_terminal_cmd
,
1182 "configure terminal",
1183 "Configuration from vty interface\n"
1184 "Configuration terminal\n")
1186 if (vty_config_lock (vty
))
1187 vty
->node
= CONFIG_NODE
;
1190 vty_outln (vty
, "VTY configuration is locked by other VTY");
1191 return CMD_WARNING_CONFIG_FAILED
;
1196 /* Enable command */
1200 "Turn on privileged mode command\n")
1202 /* If enable password is NULL, change to ENABLE_NODE */
1203 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
1204 vty
->type
== VTY_SHELL_SERV
)
1205 vty
->node
= ENABLE_NODE
;
1207 vty
->node
= AUTH_ENABLE_NODE
;
1212 /* Disable command */
1216 "Turn off privileged mode command\n")
1218 if (vty
->node
== ENABLE_NODE
)
1219 vty
->node
= VIEW_NODE
;
1223 /* Down vty node level. */
1227 "Exit current mode and down to previous mode\n")
1234 cmd_exit (struct vty
*vty
)
1240 if (vty_shell (vty
))
1243 vty
->status
= VTY_CLOSE
;
1246 vty
->node
= ENABLE_NODE
;
1247 vty_config_unlock (vty
);
1249 case INTERFACE_NODE
:
1261 case LDP_L2VPN_NODE
:
1268 vty
->node
= CONFIG_NODE
;
1271 case BGP_IPV4M_NODE
:
1272 case BGP_IPV4L_NODE
:
1273 case BGP_VPNV4_NODE
:
1274 case BGP_VPNV6_NODE
:
1275 case BGP_VRF_POLICY_NODE
:
1276 case BGP_VNC_DEFAULTS_NODE
:
1277 case BGP_VNC_NVE_GROUP_NODE
:
1278 case BGP_VNC_L2_GROUP_NODE
:
1280 case BGP_IPV6M_NODE
:
1282 case BGP_IPV6L_NODE
:
1283 vty
->node
= BGP_NODE
;
1285 case BGP_EVPN_VNI_NODE
:
1286 vty
->node
= BGP_EVPN_NODE
;
1290 vty
->node
= LDP_NODE
;
1292 case LDP_IPV4_IFACE_NODE
:
1293 vty
->node
= LDP_IPV4_NODE
;
1295 case LDP_IPV6_IFACE_NODE
:
1296 vty
->node
= LDP_IPV6_NODE
;
1298 case LDP_PSEUDOWIRE_NODE
:
1299 vty
->node
= LDP_L2VPN_NODE
;
1301 case KEYCHAIN_KEY_NODE
:
1302 vty
->node
= KEYCHAIN_NODE
;
1304 case LINK_PARAMS_NODE
:
1305 vty
->node
= INTERFACE_NODE
;
1316 "Exit current mode and down to previous mode\n")
1318 return config_exit (self
, vty
, argc
, argv
);
1322 /* End of configuration. */
1326 "End current mode and change to enable mode.")
1332 /* Nothing to do. */
1335 case INTERFACE_NODE
:
1344 case BGP_VRF_POLICY_NODE
:
1345 case BGP_VNC_DEFAULTS_NODE
:
1346 case BGP_VNC_NVE_GROUP_NODE
:
1347 case BGP_VNC_L2_GROUP_NODE
:
1348 case BGP_VPNV4_NODE
:
1349 case BGP_VPNV6_NODE
:
1351 case BGP_IPV4M_NODE
:
1352 case BGP_IPV4L_NODE
:
1354 case BGP_IPV6M_NODE
:
1356 case BGP_EVPN_VNI_NODE
:
1357 case BGP_IPV6L_NODE
:
1364 case LDP_IPV4_IFACE_NODE
:
1365 case LDP_IPV6_IFACE_NODE
:
1366 case LDP_L2VPN_NODE
:
1367 case LDP_PSEUDOWIRE_NODE
:
1370 case KEYCHAIN_KEY_NODE
:
1374 case LINK_PARAMS_NODE
:
1375 vty_config_unlock (vty
);
1376 vty
->node
= ENABLE_NODE
;
1385 DEFUN (show_version
,
1389 "Displays zebra version\n")
1391 vty_outln (vty
, "%s %s (%s).", FRR_FULL_NAME
, FRR_VERSION
,
1392 host
.name
? host
.name
: "");
1393 vty_outln (vty
, "%s%s", FRR_COPYRIGHT
, GIT_INFO
);
1394 vty_outln (vty
, "configured with:%s %s", VTYNL
,
1400 /* "Set" version ... ignore version tags */
1401 DEFUN (frr_version_defaults
,
1402 frr_version_defaults_cmd
,
1403 "frr <version|defaults> LINE...",
1404 "FRRouting global parameters\n"
1405 "version configuration was written by\n"
1406 "set of configuration defaults used\n"
1412 /* Help display function for all node. */
1416 "Description of the interactive help system\n")
1419 "Quagga VTY provides advanced help feature. When you need help,%s\
1420 anytime at the command line please press '?'.%s\
1422 If nothing matches, the help list will be empty and you must backup%s\
1423 until entering a '?' shows the available options.%s\
1424 Two styles of help are provided:%s\
1425 1. Full help is available when you are ready to enter a%s\
1426 command argument (e.g. 'show ?') and describes each possible%s\
1428 2. Partial help is provided when an abbreviated argument is entered%s\
1429 and you want to know what arguments match the input%s\
1430 (e.g. 'show me?'.)%s", VTYNL
, VTYNL
, VTYNL
,
1431 VTYNL
, VTYNL
, VTYNL
, VTYNL
, VTYNL
,
1432 VTYNL
, VTYNL
, VTYNL
, VTYNL
);
1437 permute (struct graph_node
*start
, struct vty
*vty
)
1439 static struct list
*position
= NULL
;
1440 if (!position
) position
= list_new ();
1442 struct cmd_token
*stok
= start
->data
;
1443 struct graph_node
*gnn
;
1444 struct listnode
*ln
;
1447 listnode_add (position
, start
);
1448 for (unsigned int i
= 0; i
< vector_active (start
->to
); i
++)
1450 struct graph_node
*gn
= vector_slot (start
->to
, i
);
1451 struct cmd_token
*tok
= gn
->data
;
1452 if (tok
->attr
== CMD_ATTR_HIDDEN
||
1453 tok
->attr
== CMD_ATTR_DEPRECATED
)
1455 else if (tok
->type
== END_TKN
|| gn
== start
)
1458 for (ALL_LIST_ELEMENTS_RO (position
,ln
,gnn
))
1460 struct cmd_token
*tt
= gnn
->data
;
1461 if (tt
->type
< SPECIAL_TKN
)
1462 vty_out (vty
, " %s", tt
->text
);
1465 vty_out (vty
, "...");
1466 vty_out (vty
, VTYNL
);
1471 if (stok
->type
== FORK_TKN
&& tok
->type
!= FORK_TKN
)
1472 for (ALL_LIST_ELEMENTS_RO (position
, ln
, gnn
))
1482 list_delete_node (position
, listtail(position
));
1486 cmd_list_cmds (struct vty
*vty
, int do_permute
)
1488 struct cmd_node
*node
= vector_slot (cmdvec
, vty
->node
);
1491 permute (vector_slot (node
->cmdgraph
->nodes
, 0), vty
);
1494 /* loop over all commands at this node */
1495 struct cmd_element
*element
= NULL
;
1496 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
); i
++)
1497 if ((element
= vector_slot (node
->cmd_vector
, i
)) &&
1498 element
->attr
!= CMD_ATTR_DEPRECATED
&&
1499 element
->attr
!= CMD_ATTR_HIDDEN
)
1500 vty_outln (vty
, " %s", element
->string
);
1505 /* Help display function for all node. */
1508 "list [permutations]",
1509 "Print command list\n"
1510 "Print all possible command permutations\n")
1512 return cmd_list_cmds (vty
, argc
== 2);
1515 DEFUN (show_commandtree
,
1516 show_commandtree_cmd
,
1517 "show commandtree [permutations]",
1519 "Show command tree\n"
1520 "Permutations that we are interested in\n")
1522 return cmd_list_cmds (vty
, argc
== 3);
1526 vty_write_config (struct vty
*vty
)
1529 struct cmd_node
*node
;
1531 if (vty
->type
== VTY_TERM
)
1533 vty_outln (vty
, "%sCurrent configuration:",VTYNL
);
1534 vty_outln (vty
, "!");
1537 vty_outln (vty
, "frr version %s", FRR_VER_SHORT
);
1538 vty_outln (vty
, "frr defaults %s", DFLT_NAME
);
1539 vty_outln (vty
, "!");
1541 for (i
= 0; i
< vector_active (cmdvec
); i
++)
1542 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
1543 && (node
->vtysh
|| vty
->type
!= VTY_SHELL
))
1545 if ((*node
->func
) (vty
))
1546 vty_outln (vty
, "!");
1549 if (vty
->type
== VTY_TERM
)
1551 vty_outln (vty
, "end");
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")))
1578 vty_write_config (vty
);
1585 /* Check and see if we are operating under vtysh configuration */
1586 if (host
.config
== NULL
)
1588 vty_outln (vty
,"Can't save to configuration file, using vtysh.");
1593 config_file
= host
.config
;
1596 #define O_DIRECTORY 0
1598 slash
= strrchr (config_file
, '/');
1601 char *config_dir
= XSTRDUP (MTYPE_TMP
, config_file
);
1602 config_dir
[slash
- config_file
] = '\0';
1603 dirfd
= open(config_dir
, O_DIRECTORY
| O_RDONLY
);
1604 XFREE (MTYPE_TMP
, config_dir
);
1607 dirfd
= open(".", O_DIRECTORY
| O_RDONLY
);
1608 /* if dirfd is invalid, directory sync fails, but we're still OK */
1611 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
1612 strcpy (config_file_sav
, config_file
);
1613 strcat (config_file_sav
, CONF_BACKUP_EXT
);
1616 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
1617 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
1619 /* Open file to configuration write. */
1620 fd
= mkstemp (config_file_tmp
);
1623 vty_outln (vty
, "Can't open configuration file %s.",config_file_tmp
);
1626 if (fchmod (fd
, CONFIGFILE_MASK
) != 0)
1628 vty_outln (vty
, "Can't chmod configuration file %s: %s (%d).",
1629 config_file_tmp
, safe_strerror(errno
), errno
);
1633 /* Make vty for configuration file. */
1634 file_vty
= vty_new ();
1636 file_vty
->type
= VTY_FILE
;
1638 /* Config file header print. */
1639 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1640 vty_time_print (file_vty
, 1);
1641 vty_out (file_vty
, "!\n");
1642 vty_write_config (file_vty
);
1643 vty_close (file_vty
);
1645 if (stat(config_file
, &conf_stat
) >= 0)
1647 if (unlink (config_file_sav
) != 0)
1648 if (errno
!= ENOENT
)
1650 vty_outln (vty
, "Can't unlink backup configuration file %s.",
1654 if (link (config_file
, config_file_sav
) != 0)
1656 vty_outln (vty
, "Can't backup old configuration file %s.",
1663 if (rename (config_file_tmp
, config_file
) != 0)
1665 vty_outln (vty
, "Can't save configuration file %s.",config_file
);
1671 vty_outln (vty
, "Configuration saved to %s",config_file
);
1675 if (ret
!= CMD_SUCCESS
)
1676 unlink (config_file_tmp
);
1679 XFREE (MTYPE_TMP
, config_file_tmp
);
1680 XFREE (MTYPE_TMP
, config_file_sav
);
1684 /* ALIAS_FIXME for 'write <terminal|memory>' */
1685 DEFUN (show_running_config
,
1686 show_running_config_cmd
,
1687 "show running-config",
1689 "running configuration (same as write terminal/memory)\n")
1691 return config_write (self
, vty
, argc
, argv
);
1694 /* ALIAS_FIXME for 'write file' */
1695 DEFUN (copy_runningconf_startupconf
,
1696 copy_runningconf_startupconf_cmd
,
1697 "copy running-config startup-config",
1698 "Copy configuration\n"
1699 "Copy running config to... \n"
1700 "Copy running config to startup config (same as write file)\n")
1703 vty_write_config (vty
);
1708 /* Write startup configuration into the terminal. */
1709 DEFUN (show_startup_config
,
1710 show_startup_config_cmd
,
1711 "show startup-config",
1713 "Contents of startup configuration\n")
1720 if (host
.config
== NULL
)
1723 confp
= fopen (host
.config
, "r");
1726 vty_outln (vty
, "Can't open configuration file [%s] due to '%s'",
1727 host
.config
, safe_strerror(errno
));
1731 while (fgets (buf
, BUFSIZ
, confp
))
1735 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1739 vty_outln (vty
, "%s", buf
);
1748 cmd_hostname_set (const char *hostname
)
1750 XFREE (MTYPE_HOST
, host
.name
);
1751 host
.name
= hostname
? XSTRDUP (MTYPE_HOST
, hostname
) : NULL
;
1755 /* Hostname configuration */
1756 DEFUN (config_hostname
,
1759 "Set system's network name\n"
1760 "This system's network name\n")
1762 struct cmd_token
*word
= argv
[1];
1764 if (!isalpha((int) word
->arg
[0]))
1766 vty_outln (vty
, "Please specify string starting with alphabet");
1767 return CMD_WARNING_CONFIG_FAILED
;
1770 return cmd_hostname_set (word
->arg
);
1773 DEFUN (config_no_hostname
,
1775 "no hostname [HOSTNAME]",
1777 "Reset system's network name\n"
1778 "Host name of this router\n")
1780 return cmd_hostname_set (NULL
);
1783 /* VTY interface password set. */
1784 DEFUN (config_password
,
1786 "password [(8-8)] WORD",
1787 "Assign the terminal connection password\n"
1788 "Specifies a HIDDEN password will follow\n"
1789 "The password string\n")
1793 if (argc
== 3) // '8' was specified
1796 XFREE (MTYPE_HOST
, host
.password
);
1797 host
.password
= NULL
;
1798 if (host
.password_encrypt
)
1799 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1800 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
1804 if (!isalnum (argv
[idx_8
]->arg
[0]))
1807 "Please specify string starting with alphanumeric");
1808 return CMD_WARNING_CONFIG_FAILED
;
1812 XFREE (MTYPE_HOST
, host
.password
);
1813 host
.password
= NULL
;
1817 if (host
.password_encrypt
)
1818 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1819 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
1822 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
1827 /* VTY enable password set. */
1828 DEFUN (config_enable_password
,
1829 enable_password_cmd
,
1830 "enable password [(8-8)] WORD",
1831 "Modify enable password parameters\n"
1832 "Assign the privileged level password\n"
1833 "Specifies a HIDDEN password will follow\n"
1834 "The HIDDEN 'enable' password string\n")
1839 /* Crypt type is specified. */
1842 if (argv
[idx_8
]->arg
[0] == '8')
1845 XFREE (MTYPE_HOST
, host
.enable
);
1848 if (host
.enable_encrypt
)
1849 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1850 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
1856 vty_outln (vty
, "Unknown encryption type.");
1857 return CMD_WARNING_CONFIG_FAILED
;
1861 if (!isalnum (argv
[idx_8
]->arg
[0]))
1864 "Please specify string starting with alphanumeric");
1865 return CMD_WARNING_CONFIG_FAILED
;
1869 XFREE (MTYPE_HOST
, host
.enable
);
1872 /* Plain password input. */
1875 if (host
.enable_encrypt
)
1876 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1877 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
1880 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
1885 /* VTY enable password delete. */
1886 DEFUN (no_config_enable_password
,
1887 no_enable_password_cmd
,
1888 "no enable password",
1890 "Modify enable password parameters\n"
1891 "Assign the privileged level password\n")
1894 XFREE (MTYPE_HOST
, host
.enable
);
1897 if (host
.enable_encrypt
)
1898 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1899 host
.enable_encrypt
= NULL
;
1904 DEFUN (service_password_encrypt
,
1905 service_password_encrypt_cmd
,
1906 "service password-encryption",
1907 "Set up miscellaneous service\n"
1908 "Enable encrypted passwords\n")
1917 if (host
.password_encrypt
)
1918 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1919 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
1923 if (host
.enable_encrypt
)
1924 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1925 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
1931 DEFUN (no_service_password_encrypt
,
1932 no_service_password_encrypt_cmd
,
1933 "no service password-encryption",
1935 "Set up miscellaneous service\n"
1936 "Enable encrypted passwords\n")
1943 if (host
.password_encrypt
)
1944 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1945 host
.password_encrypt
= NULL
;
1947 if (host
.enable_encrypt
)
1948 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1949 host
.enable_encrypt
= NULL
;
1954 DEFUN (config_terminal_length
,
1955 config_terminal_length_cmd
,
1956 "terminal length (0-512)",
1957 "Set terminal line parameters\n"
1958 "Set number of lines on a screen\n"
1959 "Number of lines on screen (0 for no pausing)\n")
1963 vty
->lines
= atoi (argv
[idx_number
]->arg
);
1968 DEFUN (config_terminal_no_length
,
1969 config_terminal_no_length_cmd
,
1970 "terminal no length",
1971 "Set terminal line parameters\n"
1973 "Set number of lines on a screen\n")
1979 DEFUN (service_terminal_length
,
1980 service_terminal_length_cmd
,
1981 "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")
1988 host
.lines
= atoi (argv
[idx_number
]->arg
);
1993 DEFUN (no_service_terminal_length
,
1994 no_service_terminal_length_cmd
,
1995 "no service terminal-length [(0-512)]",
1997 "Set up miscellaneous service\n"
1998 "System wide terminal length configuration\n"
1999 "Number of lines of VTY (0 means no line control)\n")
2005 DEFUN_HIDDEN (do_echo
,
2008 "Echo a message back to the vty\n"
2009 "The message to echo\n")
2013 vty_outln (vty
, "%s",
2014 ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
2016 XFREE(MTYPE_TMP
, message
);
2020 DEFUN (config_logmsg
,
2022 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
2023 "Send a message to enabled logging destinations\n"
2025 "The message to send\n")
2027 int idx_log_level
= 1;
2028 int idx_message
= 2;
2032 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2033 return CMD_ERR_NO_MATCH
;
2035 zlog(level
, "%s", ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
2037 XFREE(MTYPE_TMP
, message
);
2042 DEFUN (show_logging
,
2046 "Show current logging configuration\n")
2048 struct zlog
*zl
= zlog_default
;
2050 vty_out (vty
, "Syslog logging: ");
2051 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
2052 vty_out (vty
, "disabled");
2054 vty_out (vty
, "level %s, facility %s, ident %s",
2055 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
2056 facility_name(zl
->facility
), zl
->ident
);
2057 vty_out (vty
, VTYNL
);
2059 vty_out (vty
, "Stdout logging: ");
2060 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
2061 vty_out (vty
, "disabled");
2063 vty_out (vty
, "level %s",
2064 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
2065 vty_out (vty
, VTYNL
);
2067 vty_out (vty
, "Monitor logging: ");
2068 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
2069 vty_out (vty
, "disabled");
2071 vty_out (vty
, "level %s",
2072 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
2073 vty_out (vty
, VTYNL
);
2075 vty_out (vty
, "File logging: ");
2076 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
2078 vty_out (vty
, "disabled");
2080 vty_out (vty
, "level %s, filename %s",
2081 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
2083 vty_out (vty
, VTYNL
);
2085 vty_outln (vty
, "Protocol name: %s",
2087 vty_outln (vty
, "Record priority: %s",
2088 (zl
->record_priority
? "enabled" : "disabled"));
2089 vty_outln (vty
, "Timestamp precision: %d",
2090 zl
->timestamp_precision
);
2095 DEFUN (config_log_stdout
,
2096 config_log_stdout_cmd
,
2097 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2099 "Set stdout logging level\n"
2102 int idx_log_level
= 2;
2104 if (argc
== idx_log_level
)
2106 zlog_set_level (ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
2111 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2112 return CMD_ERR_NO_MATCH
;
2113 zlog_set_level (ZLOG_DEST_STDOUT
, level
);
2117 DEFUN (no_config_log_stdout
,
2118 no_config_log_stdout_cmd
,
2119 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2122 "Cancel logging to stdout\n"
2125 zlog_set_level (ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
2129 DEFUN (config_log_monitor
,
2130 config_log_monitor_cmd
,
2131 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2133 "Set terminal line (monitor) logging level\n"
2136 int idx_log_level
= 2;
2138 if (argc
== idx_log_level
)
2140 zlog_set_level (ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
2145 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
2146 return CMD_ERR_NO_MATCH
;
2147 zlog_set_level (ZLOG_DEST_MONITOR
, level
);
2151 DEFUN (no_config_log_monitor
,
2152 no_config_log_monitor_cmd
,
2153 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2156 "Disable terminal line (monitor) logging\n"
2159 zlog_set_level (ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
2164 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
2168 const char *fullpath
;
2170 /* Path detection. */
2171 if (! IS_DIRECTORY_SEP (*fname
))
2173 char cwd
[MAXPATHLEN
+1];
2174 cwd
[MAXPATHLEN
] = '\0';
2176 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
2178 zlog_err ("config_log_file: Unable to alloc mem!");
2179 return CMD_WARNING_CONFIG_FAILED
;
2182 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
2185 zlog_err ("config_log_file: Unable to alloc mem!");
2186 return CMD_WARNING_CONFIG_FAILED
;
2188 sprintf (p
, "%s/%s", cwd
, fname
);
2194 ret
= zlog_set_file (fullpath
, loglevel
);
2197 XFREE (MTYPE_TMP
, p
);
2201 vty_out (vty
, "can't open logfile %s\n", fname
);
2202 return CMD_WARNING_CONFIG_FAILED
;
2206 XFREE (MTYPE_HOST
, host
.logfile
);
2208 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
2210 #if defined(HAVE_CUMULUS)
2211 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2212 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2217 DEFUN (config_log_file
,
2218 config_log_file_cmd
,
2219 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2222 "Logging filename\n"
2225 int idx_filename
= 2;
2226 int idx_log_levels
= 3;
2230 if ((level
= level_match(argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2231 return CMD_ERR_NO_MATCH
;
2232 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2235 return set_log_file(vty
, argv
[idx_filename
]->arg
, zlog_default
->default_lvl
);
2238 DEFUN (no_config_log_file
,
2239 no_config_log_file_cmd
,
2240 "no log file [FILENAME [LEVEL]]",
2243 "Cancel logging to file\n"
2244 "Logging file name\n"
2250 XFREE (MTYPE_HOST
, host
.logfile
);
2252 host
.logfile
= NULL
;
2257 DEFUN (config_log_syslog
,
2258 config_log_syslog_cmd
,
2259 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2261 "Set syslog logging level\n"
2264 int idx_log_levels
= 2;
2268 if ((level
= level_match (argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2269 return CMD_ERR_NO_MATCH
;
2270 zlog_set_level (ZLOG_DEST_SYSLOG
, level
);
2275 zlog_set_level (ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2280 DEFUN (no_config_log_syslog
,
2281 no_config_log_syslog_cmd
,
2282 "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>]",
2285 "Cancel logging to syslog\n"
2289 zlog_set_level (ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2293 DEFUN (config_log_facility
,
2294 config_log_facility_cmd
,
2295 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2297 "Facility parameter for syslog messages\n"
2301 int facility
= facility_match(argv
[idx_target
]->arg
);
2303 zlog_default
->facility
= facility
;
2307 DEFUN (no_config_log_facility
,
2308 no_config_log_facility_cmd
,
2309 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2312 "Reset syslog facility to default (daemon)\n"
2315 zlog_default
->facility
= LOG_DAEMON
;
2319 DEFUN_DEPRECATED (config_log_trap
,
2320 config_log_trap_cmd
,
2321 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2323 "(Deprecated) Set logging level and default for all destinations\n"
2329 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2330 return CMD_ERR_NO_MATCH
;
2332 zlog_default
->default_lvl
= new_level
;
2333 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2334 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2335 zlog_default
->maxlvl
[i
] = new_level
;
2339 DEFUN_DEPRECATED (no_config_log_trap
,
2340 no_config_log_trap_cmd
,
2341 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2344 "Permit all logging information\n"
2347 zlog_default
->default_lvl
= LOG_DEBUG
;
2351 DEFUN (config_log_record_priority
,
2352 config_log_record_priority_cmd
,
2353 "log record-priority",
2355 "Log the priority of the message within the message\n")
2357 zlog_default
->record_priority
= 1 ;
2361 DEFUN (no_config_log_record_priority
,
2362 no_config_log_record_priority_cmd
,
2363 "no log record-priority",
2366 "Do not log the priority of the message within the message\n")
2368 zlog_default
->record_priority
= 0 ;
2372 DEFUN (config_log_timestamp_precision
,
2373 config_log_timestamp_precision_cmd
,
2374 "log timestamp precision (0-6)",
2376 "Timestamp configuration\n"
2377 "Set the timestamp precision\n"
2378 "Number of subsecond digits\n")
2381 zlog_default
->timestamp_precision
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
2385 DEFUN (no_config_log_timestamp_precision
,
2386 no_config_log_timestamp_precision_cmd
,
2387 "no log timestamp precision",
2390 "Timestamp configuration\n"
2391 "Reset the timestamp precision to the default value of 0\n")
2393 zlog_default
->timestamp_precision
= 0 ;
2398 cmd_banner_motd_file (const char *file
)
2400 int success
= CMD_SUCCESS
;
2405 rpath
= realpath (file
, p
);
2407 return CMD_ERR_NO_FILE
;
2408 in
= strstr (rpath
, SYSCONFDIR
);
2412 XFREE (MTYPE_HOST
, host
.motdfile
);
2413 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
2416 success
= CMD_WARNING_CONFIG_FAILED
;
2421 DEFUN (banner_motd_file
,
2422 banner_motd_file_cmd
,
2423 "banner motd file FILE",
2426 "Banner from a file\n"
2430 const char *filename
= argv
[idx_file
]->arg
;
2431 int cmd
= cmd_banner_motd_file (filename
);
2433 if (cmd
== CMD_ERR_NO_FILE
)
2434 vty_out (vty
, "%s does not exist", filename
);
2435 else if (cmd
== CMD_WARNING_CONFIG_FAILED
)
2436 vty_out (vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2441 DEFUN (banner_motd_default
,
2442 banner_motd_default_cmd
,
2443 "banner motd default",
2444 "Set banner string\n"
2445 "Strings for motd\n"
2448 host
.motd
= default_motd
;
2452 DEFUN (no_banner_motd
,
2456 "Set banner string\n"
2457 "Strings for motd\n")
2461 XFREE (MTYPE_HOST
, host
.motdfile
);
2462 host
.motdfile
= NULL
;
2466 /* Set config filename. Called from vty.c */
2468 host_config_set (const char *filename
)
2471 XFREE (MTYPE_HOST
, host
.config
);
2472 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
2476 host_config_get (void)
2482 install_default (enum node_type node
)
2484 install_element (node
, &config_exit_cmd
);
2485 install_element (node
, &config_quit_cmd
);
2486 install_element (node
, &config_end_cmd
);
2487 install_element (node
, &config_help_cmd
);
2488 install_element (node
, &config_list_cmd
);
2490 install_element (node
, &config_write_cmd
);
2491 install_element (node
, &show_running_config_cmd
);
2493 install_element (node
, &autocomplete_cmd
);
2496 /* Initialize command interface. Install basic nodes and commands.
2498 * terminal = 0 -- vtysh / no logging, no config control
2499 * terminal = 1 -- normal daemon
2500 * terminal = -1 -- watchfrr / no logging, but minimal config control */
2502 cmd_init (int terminal
)
2506 varhandlers
= list_new ();
2508 /* Allocate initial top vector of commands. */
2509 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
2511 /* Default host value settings. */
2513 host
.password
= NULL
;
2515 host
.logfile
= NULL
;
2517 host
.noconfig
= (terminal
< 0);
2519 host
.motd
= default_motd
;
2520 host
.motdfile
= NULL
;
2522 /* Install top nodes. */
2523 install_node (&view_node
, NULL
);
2524 install_node (&enable_node
, NULL
);
2525 install_node (&auth_node
, NULL
);
2526 install_node (&auth_enable_node
, NULL
);
2527 install_node (&config_node
, config_write_host
);
2529 /* Each node's basic commands. */
2530 install_element (VIEW_NODE
, &show_version_cmd
);
2533 install_element (VIEW_NODE
, &config_list_cmd
);
2534 install_element (VIEW_NODE
, &config_exit_cmd
);
2535 install_element (VIEW_NODE
, &config_quit_cmd
);
2536 install_element (VIEW_NODE
, &config_help_cmd
);
2537 install_element (VIEW_NODE
, &config_enable_cmd
);
2538 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
2539 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
2540 install_element (VIEW_NODE
, &show_logging_cmd
);
2541 install_element (VIEW_NODE
, &show_commandtree_cmd
);
2542 install_element (VIEW_NODE
, &echo_cmd
);
2543 install_element (VIEW_NODE
, &autocomplete_cmd
);
2548 install_element (ENABLE_NODE
, &config_end_cmd
);
2549 install_element (ENABLE_NODE
, &config_disable_cmd
);
2550 install_element (ENABLE_NODE
, &config_terminal_cmd
);
2551 install_element (ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2552 install_element (ENABLE_NODE
, &config_write_cmd
);
2553 install_element (ENABLE_NODE
, &show_running_config_cmd
);
2555 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
2559 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
2560 install_default (CONFIG_NODE
);
2563 workqueue_cmd_init ();
2567 install_element (CONFIG_NODE
, &hostname_cmd
);
2568 install_element (CONFIG_NODE
, &no_hostname_cmd
);
2569 install_element (CONFIG_NODE
, &frr_version_defaults_cmd
);
2573 install_element (CONFIG_NODE
, &password_cmd
);
2574 install_element (CONFIG_NODE
, &enable_password_cmd
);
2575 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
2577 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
2578 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
2579 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
2580 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
2581 install_element (CONFIG_NODE
, &config_log_file_cmd
);
2582 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
2583 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
2584 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
2585 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
2586 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
2587 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
2588 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
2589 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
2590 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
2591 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
2592 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
2593 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
2594 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2595 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
2596 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
2597 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
2598 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
2599 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
2601 vrf_install_commands ();
2605 grammar_sandbox_init();
2612 struct cmd_node
*cmd_node
;
2616 for (unsigned int i
= 0; i
< vector_active (cmdvec
); i
++)
2617 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
2619 // deleting the graph delets the cmd_element as well
2620 graph_delete_graph (cmd_node
->cmdgraph
);
2621 vector_free (cmd_node
->cmd_vector
);
2622 hash_clean (cmd_node
->cmd_hash
, NULL
);
2623 hash_free (cmd_node
->cmd_hash
);
2624 cmd_node
->cmd_hash
= NULL
;
2627 vector_free (cmdvec
);
2632 XFREE (MTYPE_HOST
, host
.name
);
2634 XFREE (MTYPE_HOST
, host
.password
);
2635 if (host
.password_encrypt
)
2636 XFREE (MTYPE_HOST
, host
.password_encrypt
);
2638 XFREE (MTYPE_HOST
, host
.enable
);
2639 if (host
.enable_encrypt
)
2640 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2642 XFREE (MTYPE_HOST
, host
.logfile
);
2644 XFREE (MTYPE_HOST
, host
.motdfile
);
2646 XFREE (MTYPE_HOST
, host
.config
);
2648 list_delete (varhandlers
);