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
23 * along with GNU Zebra; see the file COPYING. If not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
33 #include <lib/version.h>
39 #include "workqueue.h"
41 #include "command_match.h"
42 #include "command_parse.h"
45 DEFINE_MTYPE( LIB
, HOST
, "Host config")
46 DEFINE_MTYPE( LIB
, STRVEC
, "String vector")
47 DEFINE_MTYPE_STATIC(LIB
, CMD_TOKENS
, "Command desc")
49 /* Command vector which includes some level of command lists. Normally
50 each daemon maintains each own cmdvec. */
53 /* Host information structure. */
56 /* Standard command node structures. */
57 static struct cmd_node auth_node
=
63 static struct cmd_node view_node
=
69 static struct cmd_node auth_enable_node
=
75 static struct cmd_node enable_node
=
81 static struct cmd_node config_node
=
88 /* Default motd string. */
89 static const char *default_motd
=
91 Hello, this is " QUAGGA_PROGNAME
" (version " QUAGGA_VERSION
").\r\n\
92 " QUAGGA_COPYRIGHT
"\r\n\
96 static const struct facility_map
{
100 } syslog_facilities
[] =
102 { LOG_KERN
, "kern", 1 },
103 { LOG_USER
, "user", 2 },
104 { LOG_MAIL
, "mail", 1 },
105 { LOG_DAEMON
, "daemon", 1 },
106 { LOG_AUTH
, "auth", 1 },
107 { LOG_SYSLOG
, "syslog", 1 },
108 { LOG_LPR
, "lpr", 2 },
109 { LOG_NEWS
, "news", 1 },
110 { LOG_UUCP
, "uucp", 2 },
111 { LOG_CRON
, "cron", 1 },
113 { LOG_FTP
, "ftp", 1 },
115 { LOG_LOCAL0
, "local0", 6 },
116 { LOG_LOCAL1
, "local1", 6 },
117 { LOG_LOCAL2
, "local2", 6 },
118 { LOG_LOCAL3
, "local3", 6 },
119 { LOG_LOCAL4
, "local4", 6 },
120 { LOG_LOCAL5
, "local5", 6 },
121 { LOG_LOCAL6
, "local6", 6 },
122 { LOG_LOCAL7
, "local7", 6 },
127 facility_name(int facility
)
129 const struct facility_map
*fm
;
131 for (fm
= syslog_facilities
; fm
->name
; fm
++)
132 if (fm
->facility
== facility
)
138 facility_match(const char *str
)
140 const struct facility_map
*fm
;
142 for (fm
= syslog_facilities
; fm
->name
; fm
++)
143 if (!strncmp(str
,fm
->name
,fm
->match
))
149 level_match(const char *s
)
153 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
154 if (!strncmp (s
, zlog_priority
[level
], 2))
156 return ZLOG_DISABLED
;
159 /* This is called from main when a daemon is invoked with -v or --version. */
161 print_version (const char *progname
)
163 printf ("%s version %s\n", progname
, QUAGGA_VERSION
);
164 printf ("%s\n", QUAGGA_COPYRIGHT
);
165 printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS
);
169 /* Utility function to concatenate argv argument into a single string
170 with inserting ' ' character between each argument. */
172 argv_concat (struct cmd_token
**argv
, int argc
, int shift
)
180 for (i
= shift
; i
< argc
; i
++)
181 len
+= strlen(argv
[i
]->arg
)+1;
184 p
= str
= XMALLOC(MTYPE_TMP
, len
);
185 for (i
= shift
; i
< argc
; i
++)
188 memcpy(p
, argv
[i
]->arg
, (arglen
= strlen(argv
[i
]->arg
)));
197 * Convenience function for accessing argv data.
201 * @param text definition snippet of the desired token
202 * @param index the starting index, and where to store the
203 * index of the found token if it exists
204 * @return 1 if found, 0 otherwise
207 argv_find (struct cmd_token
**argv
, int argc
, const char *text
, int *index
)
210 for (int i
= *index
; i
< argc
&& found
== 0; i
++)
211 if ((found
= strmatch (text
, argv
[i
]->text
)))
217 cmd_hash_key (void *p
)
219 return (uintptr_t) p
;
223 cmd_hash_cmp (const void *a
, const void *b
)
228 /* Install top node of command vector. */
230 install_node (struct cmd_node
*node
,
231 int (*func
) (struct vty
*))
233 vector_set_index (cmdvec
, node
->node
, node
);
235 node
->cmdgraph
= graph_new ();
236 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
238 struct cmd_token
*token
= new_cmd_token (START_TKN
, CMD_ATTR_NORMAL
, NULL
, NULL
);
239 graph_new_node (node
->cmdgraph
, token
, (void (*)(void *)) &del_cmd_token
);
240 node
->cmd_hash
= hash_create (cmd_hash_key
, cmd_hash_cmp
);
244 * Tokenizes a string, storing tokens in a vector.
245 * Whitespace is ignored.
247 * Delimiter string = " \n\r\t".
249 * @param string to tokenize
250 * @return tokenized string
253 cmd_make_strvec (const char *string
)
255 if (!string
) return NULL
;
257 char *copy
, *copystart
;
258 copystart
= copy
= XSTRDUP (MTYPE_TMP
, string
);
260 // skip leading whitespace
261 while (isspace ((int) *copy
) && *copy
!= '\0') copy
++;
263 // if the entire string was whitespace or a comment, return
264 if (*copy
== '\0' || *copy
== '!' || *copy
== '#')
266 XFREE (MTYPE_TMP
, copystart
);
270 vector strvec
= vector_init (VECTOR_MIN_SIZE
);
271 const char *delim
= " \n\r\t", *tok
= NULL
;
274 tok
= strsep (©
, delim
);
276 vector_set (strvec
, XSTRDUP (MTYPE_STRVEC
, tok
));
279 XFREE (MTYPE_TMP
, copystart
);
283 /* Free allocated string vector. */
285 cmd_free_strvec (vector v
)
293 for (i
= 0; i
< vector_active (v
); i
++)
294 if ((cp
= vector_slot (v
, i
)) != NULL
)
295 XFREE (MTYPE_STRVEC
, cp
);
301 cmd_concat_strvec (vector v
)
304 for (unsigned int i
= 0; i
< vector_active (v
); i
++)
305 if (vector_slot (v
, i
))
306 strsize
+= strlen ((char *) vector_slot (v
, i
)) + 1;
308 char *concatenated
= calloc (sizeof (char), strsize
);
309 for (unsigned int i
= 0; i
< vector_active (v
); i
++)
311 strlcat (concatenated
, (char *) vector_slot (v
, i
), strsize
);
312 strlcat (concatenated
, " ", strsize
);
318 /* Return prompt character of specified node. */
320 cmd_prompt (enum node_type node
)
322 struct cmd_node
*cnode
;
324 cnode
= vector_slot (cmdvec
, node
);
325 return cnode
->prompt
;
328 /* Install a command into a node. */
330 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
332 struct cmd_node
*cnode
;
334 /* cmd_init hasn't been called */
337 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
342 cnode
= vector_slot (cmdvec
, ntype
);
346 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
351 if (hash_lookup (cnode
->cmd_hash
, cmd
) != NULL
)
354 "Multiple command installs to node %d of command:\n%s\n",
359 assert (hash_get (cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
361 command_parse_format (cnode
->cmdgraph
, cmd
);
362 vector_set (cnode
->cmd_vector
, cmd
);
364 if (ntype
== VIEW_NODE
)
365 install_element (ENABLE_NODE
, cmd
);
368 static const unsigned char itoa64
[] =
369 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
372 to64(char *s
, long v
, int n
)
376 *s
++ = itoa64
[v
&0x3f];
382 zencrypt (const char *passwd
)
386 char *crypt (const char *, const char *);
390 to64(&salt
[0], random(), 3);
391 to64(&salt
[3], tv
.tv_usec
, 3);
394 return crypt (passwd
, salt
);
397 /* This function write configuration of this host. */
399 config_write_host (struct vty
*vty
)
402 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
406 if (host
.password_encrypt
)
407 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
408 if (host
.enable_encrypt
)
409 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
414 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
416 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
419 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
421 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
423 vty_out (vty
, "log trap %s%s",
424 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
427 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
429 vty_out (vty
, "log file %s", host
.logfile
);
430 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
432 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
433 vty_out (vty
, "%s", VTY_NEWLINE
);
436 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
438 vty_out (vty
, "log stdout");
439 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
441 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
442 vty_out (vty
, "%s", VTY_NEWLINE
);
445 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
446 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
447 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
448 vty_out(vty
,"log monitor %s%s",
449 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
451 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
453 vty_out (vty
, "log syslog");
454 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
456 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
457 vty_out (vty
, "%s", VTY_NEWLINE
);
460 if (zlog_default
->facility
!= LOG_DAEMON
)
461 vty_out (vty
, "log facility %s%s",
462 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
464 if (zlog_default
->record_priority
== 1)
465 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
467 if (zlog_default
->timestamp_precision
> 0)
468 vty_out (vty
, "log timestamp precision %d%s",
469 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
472 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
475 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
478 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
482 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
483 else if (! host
.motd
)
484 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
489 /* Utility function for getting command graph. */
490 static struct graph
*
491 cmd_node_graph (vector v
, enum node_type ntype
)
493 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
494 return cnode
->cmdgraph
;
498 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
499 if ( first_word
!= NULL
&&
502 node
!= AUTH_ENABLE_NODE
&&
503 node
!= ENABLE_NODE
&&
504 0 == strcmp( "do", first_word
) )
510 * Compare function for cmd_token.
511 * Used with qsort to sort command completions.
514 compare_completions (const void *fst
, const void *snd
)
516 struct cmd_token
*first
= *(struct cmd_token
**) fst
,
517 *secnd
= *(struct cmd_token
**) snd
;
518 return strcmp (first
->text
, secnd
->text
);
522 * Takes a list of completions returned by command_complete,
523 * dedeuplicates them based on both text and description,
524 * sorts them, and returns them as a vector.
526 * @param completions linked list of cmd_token
527 * @return deduplicated and sorted vector with
530 completions_to_vec (struct list
*completions
)
532 vector comps
= vector_init (VECTOR_MIN_SIZE
);
535 struct cmd_token
*token
, *cr
= NULL
;
536 unsigned int i
, exists
;
537 for (ALL_LIST_ELEMENTS_RO(completions
,ln
,token
))
539 if (token
->type
== END_TKN
&& (cr
= token
))
542 // linear search for token in completions vector
544 for (i
= 0; i
< vector_active (comps
) && !exists
; i
++)
546 struct cmd_token
*curr
= vector_slot (comps
, i
);
547 exists
= !strcmp (curr
->text
, token
->text
) &&
548 !strcmp (curr
->desc
, token
->desc
);
552 vector_set (comps
, token
);
557 vector_active (comps
),
559 &compare_completions
);
561 // make <cr> the first element, if it is present
564 vector_set_index (comps
, vector_active (comps
), NULL
);
565 memmove (comps
->index
+ 1, comps
->index
, (comps
->alloced
- 1) * sizeof (void *));
566 vector_set_index (comps
, 0, cr
);
572 * Generates a vector of cmd_token representing possible completions
573 * on the current input.
575 * @param vline the vectorized input line
576 * @param vty the vty with the node to match on
577 * @param status pointer to matcher status code
578 * @return vector of struct cmd_token * with possible completions
581 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
)
583 struct list
*completions
;
584 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
586 enum matcher_rv rv
= command_complete (cmdgraph
, vline
, &completions
);
588 if (MATCHER_ERROR(rv
))
590 *status
= CMD_ERR_NO_MATCH
;
594 vector comps
= completions_to_vec (completions
);
595 list_delete (completions
);
597 // set status code appropriately
598 switch (vector_active (comps
))
601 *status
= CMD_ERR_NO_MATCH
;
604 *status
= CMD_COMPLETE_FULL_MATCH
;
607 *status
= CMD_COMPLETE_LIST_MATCH
;
614 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
618 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
620 enum node_type onode
;
621 vector shifted_vline
;
625 vty
->node
= ENABLE_NODE
;
626 /* We can try it on enable node, cos' the vty is authenticated */
628 shifted_vline
= vector_init (vector_count(vline
));
630 for (index
= 1; index
< vector_active (vline
); index
++)
632 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
635 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
);
637 vector_free(shifted_vline
);
642 return cmd_complete_command_real (vline
, vty
, status
);
646 * Generate possible tab-completions for the given input. This function only
647 * returns results that would result in a valid command if used as Readline
648 * completions (as is the case in vtysh). For instance, if the passed vline ends
649 * with '4.3.2', the strings 'A.B.C.D' and 'A.B.C.D/M' will _not_ be returned.
651 * @param vline vectorized input line
653 * @param status location to store matcher status code in
654 * @return set of valid strings for use with Readline as tab-completions.
658 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
661 int original_node
= vty
->node
;
662 vector input_line
= vector_init (vector_count (vline
));
664 // if the first token is 'do' we'll want to execute the command in the enable node
665 int do_shortcut
= cmd_try_do_shortcut (vty
->node
, vector_slot (vline
, 0));
666 vty
->node
= do_shortcut
? ENABLE_NODE
: original_node
;
668 // construct the input line we'll be matching on
669 unsigned int offset
= (do_shortcut
) ? 1 : 0;
670 for (unsigned index
= 0; index
+ offset
< vector_active (vline
); index
++)
671 vector_set_index (input_line
, index
+ offset
, vector_lookup (vline
, index
));
673 // get token completions -- this is a copying operation
674 vector comps
= NULL
, initial_comps
;
675 initial_comps
= cmd_complete_command_real (input_line
, vty
, status
);
677 if (!MATCHER_ERROR (*status
))
679 assert (initial_comps
);
680 // filter out everything that is not suitable for a tab-completion
681 comps
= vector_init (VECTOR_MIN_SIZE
);
682 for (unsigned int i
= 0; i
< vector_active(initial_comps
); i
++)
684 struct cmd_token
*token
= vector_slot (initial_comps
, i
);
685 if (token
->type
== WORD_TKN
)
686 vector_set (comps
, token
);
688 vector_free (initial_comps
);
690 // copy completions text into an array of char*
691 ret
= XMALLOC (MTYPE_TMP
, (vector_active (comps
)+1) * sizeof (char *));
693 for (i
= 0; i
< vector_active (comps
); i
++)
695 struct cmd_token
*token
= vector_slot (comps
, i
);
696 ret
[i
] = XSTRDUP (MTYPE_TMP
, token
->text
);
697 vector_unset (comps
, i
);
699 // set the last element to NULL, because this array is used in
700 // a Readline completion_generator function which expects NULL
701 // as a sentinel value
707 // comps should always be null here
710 // free the adjusted input line
711 vector_free (input_line
);
713 // reset vty->node to its original value
714 vty
->node
= original_node
;
719 /* return parent node */
720 /* MUST eventually converge on CONFIG_NODE */
722 node_parent ( enum node_type node
)
726 assert (node
> CONFIG_NODE
);
733 case BGP_ENCAPV6_NODE
:
734 case BGP_VNC_DEFAULTS_NODE
:
735 case BGP_VNC_NVE_GROUP_NODE
:
736 case BGP_VNC_L2_GROUP_NODE
:
743 case KEYCHAIN_KEY_NODE
:
746 case LINK_PARAMS_NODE
:
747 ret
= INTERFACE_NODE
;
753 case LDP_IPV4_IFACE_NODE
:
756 case LDP_IPV6_IFACE_NODE
:
759 case LDP_PSEUDOWIRE_NODE
:
760 ret
= LDP_L2VPN_NODE
;
770 /* Execute command by argument vline vector. */
772 cmd_execute_command_real (vector vline
,
773 enum filter_type filter
,
775 const struct cmd_element
**cmd
)
777 struct list
*argv_list
;
778 enum matcher_rv status
;
779 const struct cmd_element
*matched_element
= NULL
;
781 struct graph
*cmdgraph
= cmd_node_graph (cmdvec
, vty
->node
);
782 status
= command_match (cmdgraph
, vline
, &argv_list
, &matched_element
);
785 *cmd
= matched_element
;
787 // if matcher error, return corresponding CMD_ERR
788 if (MATCHER_ERROR(status
))
792 case MATCHER_INCOMPLETE
:
793 return CMD_ERR_INCOMPLETE
;
794 case MATCHER_AMBIGUOUS
:
795 return CMD_ERR_AMBIGUOUS
;
797 return CMD_ERR_NO_MATCH
;
801 // build argv array from argv list
802 struct cmd_token
**argv
= XMALLOC (MTYPE_TMP
, argv_list
->count
* sizeof (struct cmd_token
*));
804 struct cmd_token
*token
;
806 for (ALL_LIST_ELEMENTS_RO(argv_list
,ln
,token
))
809 int argc
= argv_list
->count
;
812 if (matched_element
->daemon
)
813 ret
= CMD_SUCCESS_DAEMON
;
815 ret
= matched_element
->func (matched_element
, vty
, argc
, argv
);
817 // delete list and cmd_token's in it
818 list_delete (argv_list
);
819 XFREE (MTYPE_TMP
, argv
);
825 * Execute a given command, handling things like "do ..." and checking
826 * whether the given command might apply at a parent node if doesn't
827 * apply for the current node.
829 * @param vline Command line input, vector of char* where each element is
831 * @param vty The vty context in which the command should be executed.
832 * @param cmd Pointer where the struct cmd_element of the matched command
833 * will be stored, if any. May be set to NULL if this info is
835 * @param vtysh If set != 0, don't lookup the command at parent nodes.
836 * @return The status of the command that has been executed or an error code
837 * as to why no command could be executed.
840 cmd_execute_command (vector vline
, struct vty
*vty
,
841 const struct cmd_element
**cmd
,
844 int ret
, saved_ret
= 0;
845 enum node_type onode
, try_node
;
847 onode
= try_node
= vty
->node
;
849 if (cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0)))
851 vector shifted_vline
;
854 vty
->node
= ENABLE_NODE
;
855 /* We can try it on enable node, cos' the vty is authenticated */
857 shifted_vline
= vector_init (vector_count(vline
));
859 for (index
= 1; index
< vector_active (vline
); index
++)
860 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
862 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
864 vector_free(shifted_vline
);
869 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
874 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
876 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
877 while (vty
->node
> CONFIG_NODE
)
879 try_node
= node_parent(try_node
);
880 vty
->node
= try_node
;
881 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
882 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
885 /* no command succeeded, reset the vty to the original node */
889 /* return command status for original node */
894 * Execute a given command, matching it strictly against the current node.
895 * This mode is used when reading config files.
897 * @param vline Command line input, vector of char* where each element is
899 * @param vty The vty context in which the command should be executed.
900 * @param cmd Pointer where the struct cmd_element* of the matched command
901 * will be stored, if any. May be set to NULL if this info is
903 * @return The status of the command that has been executed or an error code
904 * as to why no command could be executed.
907 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
908 const struct cmd_element
**cmd
)
910 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
914 * Parse one line of config, walking up the parse tree attempting to find a match
916 * @param vty The vty context in which the command should be executed.
917 * @param cmd Pointer where the struct cmd_element* of the match command
918 * will be stored, if any. May be set to NULL if this info is
920 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
922 * @return The status of the command that has been executed or an error code
923 * as to why no command could be executed.
926 command_config_read_one_line (struct vty
*vty
, const struct cmd_element
**cmd
, int use_daemon
)
932 vline
= cmd_make_strvec (vty
->buf
);
934 /* In case of comment line */
938 /* Execute configuration command : this is strict match */
939 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
941 // Climb the tree and try the command again at each node
942 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
943 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
944 ret
!= CMD_SUCCESS
&&
945 ret
!= CMD_WARNING
&&
946 vty
->node
!= CONFIG_NODE
) {
948 saved_node
= vty
->node
;
950 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
951 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
952 ret
!= CMD_SUCCESS
&&
953 ret
!= CMD_WARNING
&&
954 vty
->node
> CONFIG_NODE
) {
955 vty
->node
= node_parent(vty
->node
);
956 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
959 // If climbing the tree did not work then ignore the command and
960 // stay at the same node
961 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
962 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
963 ret
!= CMD_SUCCESS
&&
966 vty
->node
= saved_node
;
970 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
971 memcpy (vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
973 cmd_free_strvec (vline
);
978 /* Configuration make from file. */
980 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
982 int ret
, error_ret
=0;
985 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
990 ret
= command_config_read_one_line (vty
, NULL
, 0);
992 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
993 ret
!= CMD_ERR_NOTHING_TODO
)
1004 /* Configuration from terminal */
1005 DEFUN (config_terminal
,
1006 config_terminal_cmd
,
1007 "configure terminal",
1008 "Configuration from vty interface\n"
1009 "Configuration terminal\n")
1011 if (vty_config_lock (vty
))
1012 vty
->node
= CONFIG_NODE
;
1015 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
1021 /* Enable command */
1025 "Turn on privileged mode command\n")
1027 /* If enable password is NULL, change to ENABLE_NODE */
1028 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
1029 vty
->type
== VTY_SHELL_SERV
)
1030 vty
->node
= ENABLE_NODE
;
1032 vty
->node
= AUTH_ENABLE_NODE
;
1037 /* Disable command */
1041 "Turn off privileged mode command\n")
1043 if (vty
->node
== ENABLE_NODE
)
1044 vty
->node
= VIEW_NODE
;
1048 /* Down vty node level. */
1052 "Exit current mode and down to previous mode\n")
1059 cmd_exit (struct vty
*vty
)
1065 if (vty_shell (vty
))
1068 vty
->status
= VTY_CLOSE
;
1071 vty
->node
= ENABLE_NODE
;
1072 vty_config_unlock (vty
);
1074 case INTERFACE_NODE
:
1084 case LDP_L2VPN_NODE
:
1091 vty
->node
= CONFIG_NODE
;
1094 case BGP_IPV4M_NODE
:
1095 case BGP_VPNV4_NODE
:
1096 case BGP_VPNV6_NODE
:
1097 case BGP_ENCAP_NODE
:
1098 case BGP_ENCAPV6_NODE
:
1099 case BGP_VNC_DEFAULTS_NODE
:
1100 case BGP_VNC_NVE_GROUP_NODE
:
1101 case BGP_VNC_L2_GROUP_NODE
:
1103 case BGP_IPV6M_NODE
:
1104 vty
->node
= BGP_NODE
;
1108 vty
->node
= LDP_NODE
;
1110 case LDP_IPV4_IFACE_NODE
:
1111 vty
->node
= LDP_IPV4_NODE
;
1113 case LDP_IPV6_IFACE_NODE
:
1114 vty
->node
= LDP_IPV6_NODE
;
1116 case LDP_PSEUDOWIRE_NODE
:
1117 vty
->node
= LDP_L2VPN_NODE
;
1119 case KEYCHAIN_KEY_NODE
:
1120 vty
->node
= KEYCHAIN_NODE
;
1122 case LINK_PARAMS_NODE
:
1123 vty
->node
= INTERFACE_NODE
;
1134 "Exit current mode and down to previous mode\n")
1136 return config_exit (self
, vty
, argc
, argv
);
1140 /* End of configuration. */
1144 "End current mode and change to enable mode.")
1150 /* Nothing to do. */
1153 case INTERFACE_NODE
:
1160 case BGP_ENCAP_NODE
:
1161 case BGP_ENCAPV6_NODE
:
1162 case BGP_VNC_DEFAULTS_NODE
:
1163 case BGP_VNC_NVE_GROUP_NODE
:
1164 case BGP_VNC_L2_GROUP_NODE
:
1165 case BGP_VPNV4_NODE
:
1166 case BGP_VPNV6_NODE
:
1168 case BGP_IPV4M_NODE
:
1170 case BGP_IPV6M_NODE
:
1177 case LDP_IPV4_IFACE_NODE
:
1178 case LDP_IPV6_IFACE_NODE
:
1179 case LDP_L2VPN_NODE
:
1180 case LDP_PSEUDOWIRE_NODE
:
1183 case KEYCHAIN_KEY_NODE
:
1187 case LINK_PARAMS_NODE
:
1188 vty_config_unlock (vty
);
1189 vty
->node
= ENABLE_NODE
;
1198 DEFUN (show_version
,
1202 "Displays zebra version\n")
1204 vty_out (vty
, "Quagga %s (%s).%s", QUAGGA_VERSION
, host
.name
?host
.name
:"",
1206 vty_out (vty
, "%s%s%s", QUAGGA_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
1207 vty_out (vty
, "configured with:%s %s%s", VTY_NEWLINE
,
1208 QUAGGA_CONFIG_ARGS
, VTY_NEWLINE
);
1213 /* Help display function for all node. */
1217 "Description of the interactive help system\n")
1220 "Quagga VTY provides advanced help feature. When you need help,%s\
1221 anytime at the command line please press '?'.%s\
1223 If nothing matches, the help list will be empty and you must backup%s\
1224 until entering a '?' shows the available options.%s\
1225 Two styles of help are provided:%s\
1226 1. Full help is available when you are ready to enter a%s\
1227 command argument (e.g. 'show ?') and describes each possible%s\
1229 2. Partial help is provided when an abbreviated argument is entered%s\
1230 and you want to know what arguments match the input%s\
1231 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
1232 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
1233 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
1238 permute (struct graph_node
*start
, struct vty
*vty
)
1240 static struct list
*position
= NULL
;
1241 if (!position
) position
= list_new ();
1244 listnode_add (position
, start
);
1245 for (unsigned int i
= 0; i
< vector_active (start
->to
); i
++)
1247 struct graph_node
*gn
= vector_slot (start
->to
, i
);
1248 struct cmd_token
*tok
= gn
->data
;
1249 if (tok
->attr
== CMD_ATTR_HIDDEN
||
1250 tok
->attr
== CMD_ATTR_DEPRECATED
)
1252 else if (tok
->type
== END_TKN
|| gn
== start
)
1254 struct graph_node
*gnn
;
1255 struct listnode
*ln
;
1257 for (ALL_LIST_ELEMENTS_RO (position
,ln
,gnn
))
1259 struct cmd_token
*tt
= gnn
->data
;
1260 if (tt
->type
< SELECTOR_TKN
)
1261 vty_out (vty
, " %s", tt
->text
);
1264 vty_out (vty
, "...");
1265 vty_out (vty
, VTY_NEWLINE
);
1270 list_delete_node (position
, listtail(position
));
1274 cmd_list_cmds (struct vty
*vty
, int do_permute
)
1276 struct cmd_node
*node
= vector_slot (cmdvec
, vty
->node
);
1279 permute (vector_slot (node
->cmdgraph
->nodes
, 0), vty
);
1282 /* loop over all commands at this node */
1283 struct cmd_element
*element
= NULL
;
1284 for (unsigned int i
= 0; i
< vector_active(node
->cmd_vector
); i
++)
1285 if ((element
= vector_slot (node
->cmd_vector
, i
)) &&
1286 element
->attr
!= CMD_ATTR_DEPRECATED
&&
1287 element
->attr
!= CMD_ATTR_HIDDEN
)
1288 vty_out (vty
, " %s%s", element
->string
, VTY_NEWLINE
);
1293 /* Help display function for all node. */
1296 "list [permutations]",
1297 "Print command list\n"
1298 "Print all possible command permutations\n")
1300 return cmd_list_cmds (vty
, argc
== 2);
1303 DEFUN (show_commandtree
,
1304 show_commandtree_cmd
,
1305 "show commandtree [permutations]",
1307 "Show command tree\n")
1309 return cmd_list_cmds (vty
, argc
== 3);
1312 /* Write current configuration into file. */
1314 DEFUN (config_write
,
1316 "write [<file|memory|terminal>]",
1317 "Write running configuration to memory, network, or terminal\n"
1318 "Write to configuration file\n"
1319 "Write configuration currently in memory\n"
1320 "Write configuration to terminal\n")
1325 struct cmd_node
*node
;
1327 char *config_file_tmp
= NULL
;
1328 char *config_file_sav
= NULL
;
1329 int ret
= CMD_WARNING
;
1330 struct vty
*file_vty
;
1331 struct stat conf_stat
;
1333 // if command was 'write terminal', 'write memory' or 'show running-config'
1334 if (argc
== 2 && (!strcmp(argv
[idx_type
]->text
, "terminal") ||
1335 !strcmp(argv
[idx_type
]->text
, "memory") ||
1336 !strcmp(argv
[0]->text
, "show")))
1338 if (vty
->type
== VTY_SHELL_SERV
)
1340 for (i
= 0; i
< vector_active (cmdvec
); i
++)
1341 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
1343 if ((*node
->func
) (vty
))
1344 vty_out (vty
, "!%s", VTY_NEWLINE
);
1349 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
1351 vty_out (vty
, "!%s", VTY_NEWLINE
);
1353 for (i
= 0; i
< vector_active (cmdvec
); i
++)
1354 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
1356 if ((*node
->func
) (vty
))
1357 vty_out (vty
, "!%s", VTY_NEWLINE
);
1359 vty_out (vty
, "end%s",VTY_NEWLINE
);
1367 /* Check and see if we are operating under vtysh configuration */
1368 if (host
.config
== NULL
)
1370 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
1376 config_file
= host
.config
;
1379 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
1380 strcpy (config_file_sav
, config_file
);
1381 strcat (config_file_sav
, CONF_BACKUP_EXT
);
1384 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
1385 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
1387 /* Open file to configuration write. */
1388 fd
= mkstemp (config_file_tmp
);
1391 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
1396 /* Make vty for configuration file. */
1397 file_vty
= vty_new ();
1399 file_vty
->type
= VTY_FILE
;
1401 /* Config file header print. */
1402 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
1403 vty_time_print (file_vty
, 1);
1404 vty_out (file_vty
, "!\n");
1406 for (i
= 0; i
< vector_active (cmdvec
); i
++)
1407 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
1409 if ((*node
->func
) (file_vty
))
1410 vty_out (file_vty
, "!\n");
1412 vty_close (file_vty
);
1414 if (stat(config_file
, &conf_stat
) >= 0)
1416 if (unlink (config_file_sav
) != 0)
1417 if (errno
!= ENOENT
)
1419 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
1423 if (link (config_file
, config_file_sav
) != 0)
1425 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
1430 if (unlink (config_file
) != 0)
1432 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
1437 if (link (config_file_tmp
, config_file
) != 0)
1439 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
1445 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
1447 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
1448 config_file
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
1452 vty_out (vty
, "Configuration saved to %s%s", config_file
,
1457 unlink (config_file_tmp
);
1458 XFREE (MTYPE_TMP
, config_file_tmp
);
1459 XFREE (MTYPE_TMP
, config_file_sav
);
1463 /* ALIAS_FIXME for 'write <terminal|memory>' */
1464 DEFUN (show_running_config
,
1465 show_running_config_cmd
,
1466 "show running-config",
1468 "running configuration (same as write terminal/memory)\n")
1470 return config_write (self
, vty
, argc
, argv
);
1473 /* ALIAS_FIXME for 'write file' */
1474 DEFUN (copy_runningconf_startupconf
,
1475 copy_runningconf_startupconf_cmd
,
1476 "copy running-config startup-config",
1477 "Copy configuration\n"
1478 "Copy running config to... \n"
1479 "Copy running config to startup config (same as write file)\n")
1481 return config_write (self
, vty
, argc
, argv
);
1485 /* Write startup configuration into the terminal. */
1486 DEFUN (show_startup_config
,
1487 show_startup_config_cmd
,
1488 "show startup-config",
1490 "Contents of startup configuration\n")
1497 if (host
.config
== NULL
)
1500 confp
= fopen (host
.config
, "r");
1503 vty_out (vty
, "Can't open configuration file [%s] due to '%s'%s",
1504 host
.config
, safe_strerror(errno
), VTY_NEWLINE
);
1508 while (fgets (buf
, BUFSIZ
, confp
))
1512 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
1516 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
1524 /* Hostname configuration */
1525 DEFUN (config_hostname
,
1528 "Set system's network name\n"
1529 "This system's network name\n")
1531 struct cmd_token
*word
= argv
[1];
1533 if (!isalpha((int) word
->arg
[0]))
1535 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
1540 XFREE (MTYPE_HOST
, host
.name
);
1542 host
.name
= XSTRDUP (MTYPE_HOST
, word
->arg
);
1546 DEFUN (config_no_hostname
,
1548 "no hostname [HOSTNAME]",
1550 "Reset system's network name\n"
1551 "Host name of this router\n")
1554 XFREE (MTYPE_HOST
, host
.name
);
1559 /* VTY interface password set. */
1560 DEFUN (config_password
,
1562 "password [(8-8)] WORD",
1563 "Assign the terminal connection password\n"
1564 "Specifies a HIDDEN password will follow\n"
1565 "The password string\n")
1569 if (argc
== 3) // '8' was specified
1572 XFREE (MTYPE_HOST
, host
.password
);
1573 host
.password
= NULL
;
1574 if (host
.password_encrypt
)
1575 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1576 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
1580 if (!isalnum (argv
[idx_8
]->arg
[0]))
1583 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
1588 XFREE (MTYPE_HOST
, host
.password
);
1589 host
.password
= NULL
;
1593 if (host
.password_encrypt
)
1594 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1595 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
1598 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
1603 /* VTY enable password set. */
1604 DEFUN (config_enable_password
,
1605 enable_password_cmd
,
1606 "enable password [(8-8)] WORD",
1607 "Modify enable password parameters\n"
1608 "Assign the privileged level password\n"
1609 "Specifies a HIDDEN password will follow\n"
1610 "The HIDDEN 'enable' password string\n")
1615 /* Crypt type is specified. */
1618 if (argv
[idx_8
]->arg
[0] == '8')
1621 XFREE (MTYPE_HOST
, host
.enable
);
1624 if (host
.enable_encrypt
)
1625 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1626 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[idx_word
]->arg
);
1632 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
1637 if (!isalnum (argv
[idx_8
]->arg
[0]))
1640 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
1645 XFREE (MTYPE_HOST
, host
.enable
);
1648 /* Plain password input. */
1651 if (host
.enable_encrypt
)
1652 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1653 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[idx_8
]->arg
));
1656 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[idx_8
]->arg
);
1661 /* VTY enable password delete. */
1662 DEFUN (no_config_enable_password
,
1663 no_enable_password_cmd
,
1664 "no enable password",
1666 "Modify enable password parameters\n"
1667 "Assign the privileged level password\n")
1670 XFREE (MTYPE_HOST
, host
.enable
);
1673 if (host
.enable_encrypt
)
1674 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1675 host
.enable_encrypt
= NULL
;
1680 DEFUN (service_password_encrypt
,
1681 service_password_encrypt_cmd
,
1682 "service password-encryption",
1683 "Set up miscellaneous service\n"
1684 "Enable encrypted passwords\n")
1693 if (host
.password_encrypt
)
1694 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1695 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
1699 if (host
.enable_encrypt
)
1700 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1701 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
1707 DEFUN (no_service_password_encrypt
,
1708 no_service_password_encrypt_cmd
,
1709 "no service password-encryption",
1711 "Set up miscellaneous service\n"
1712 "Enable encrypted passwords\n")
1719 if (host
.password_encrypt
)
1720 XFREE (MTYPE_HOST
, host
.password_encrypt
);
1721 host
.password_encrypt
= NULL
;
1723 if (host
.enable_encrypt
)
1724 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
1725 host
.enable_encrypt
= NULL
;
1730 DEFUN (config_terminal_length
,
1731 config_terminal_length_cmd
,
1732 "terminal length (0-512)",
1733 "Set terminal line parameters\n"
1734 "Set number of lines on a screen\n"
1735 "Number of lines on screen (0 for no pausing)\n")
1739 char *endptr
= NULL
;
1741 lines
= strtol (argv
[idx_number
]->arg
, &endptr
, 10);
1742 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
1744 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
1752 DEFUN (config_terminal_no_length
,
1753 config_terminal_no_length_cmd
,
1754 "terminal no length",
1755 "Set terminal line parameters\n"
1757 "Set number of lines on a screen\n")
1763 DEFUN (service_terminal_length
,
1764 service_terminal_length_cmd
,
1765 "service terminal-length (0-512)",
1766 "Set up miscellaneous service\n"
1767 "System wide terminal length configuration\n"
1768 "Number of lines of VTY (0 means no line control)\n")
1772 char *endptr
= NULL
;
1774 lines
= strtol (argv
[idx_number
]->arg
, &endptr
, 10);
1775 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
1777 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
1785 DEFUN (no_service_terminal_length
,
1786 no_service_terminal_length_cmd
,
1787 "no service terminal-length [(0-512)]",
1789 "Set up miscellaneous service\n"
1790 "System wide terminal length configuration\n"
1791 "Number of lines of VTY (0 means no line control)\n")
1797 DEFUN_HIDDEN (do_echo
,
1800 "Echo a message back to the vty\n"
1801 "The message to echo\n")
1805 vty_out (vty
, "%s%s", ((message
= argv_concat (argv
, argc
, 1)) ? message
: ""),
1808 XFREE(MTYPE_TMP
, message
);
1812 DEFUN (config_logmsg
,
1814 "logmsg <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> MESSAGE...",
1815 "Send a message to enabled logging destinations\n"
1817 "The message to send\n")
1819 int idx_log_level
= 1;
1820 int idx_message
= 2;
1824 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
1825 return CMD_ERR_NO_MATCH
;
1827 zlog(NULL
, level
, "%s", ((message
= argv_concat(argv
, argc
, idx_message
)) ? message
: ""));
1829 XFREE(MTYPE_TMP
, message
);
1834 DEFUN (show_logging
,
1838 "Show current logging configuration\n")
1840 struct zlog
*zl
= zlog_default
;
1842 vty_out (vty
, "Syslog logging: ");
1843 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
1844 vty_out (vty
, "disabled");
1846 vty_out (vty
, "level %s, facility %s, ident %s",
1847 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
1848 facility_name(zl
->facility
), zl
->ident
);
1849 vty_out (vty
, "%s", VTY_NEWLINE
);
1851 vty_out (vty
, "Stdout logging: ");
1852 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
1853 vty_out (vty
, "disabled");
1855 vty_out (vty
, "level %s",
1856 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
1857 vty_out (vty
, "%s", VTY_NEWLINE
);
1859 vty_out (vty
, "Monitor logging: ");
1860 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
1861 vty_out (vty
, "disabled");
1863 vty_out (vty
, "level %s",
1864 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
1865 vty_out (vty
, "%s", VTY_NEWLINE
);
1867 vty_out (vty
, "File logging: ");
1868 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
1870 vty_out (vty
, "disabled");
1872 vty_out (vty
, "level %s, filename %s",
1873 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
1875 vty_out (vty
, "%s", VTY_NEWLINE
);
1877 vty_out (vty
, "Protocol name: %s%s",
1878 zlog_proto_names
[zl
->protocol
], VTY_NEWLINE
);
1879 vty_out (vty
, "Record priority: %s%s",
1880 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
1881 vty_out (vty
, "Timestamp precision: %d%s",
1882 zl
->timestamp_precision
, VTY_NEWLINE
);
1887 DEFUN (config_log_stdout
,
1888 config_log_stdout_cmd
,
1889 "log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
1891 "Set stdout logging level\n"
1894 int idx_log_level
= 2;
1896 if (argc
== idx_log_level
)
1898 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
1903 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
1904 return CMD_ERR_NO_MATCH
;
1905 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, level
);
1909 DEFUN (no_config_log_stdout
,
1910 no_config_log_stdout_cmd
,
1911 "no log stdout [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
1914 "Cancel logging to stdout\n"
1917 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
1921 DEFUN (config_log_monitor
,
1922 config_log_monitor_cmd
,
1923 "log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
1925 "Set terminal line (monitor) logging level\n"
1928 int idx_log_level
= 2;
1930 if (argc
== idx_log_level
)
1932 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
1937 if ((level
= level_match(argv
[idx_log_level
]->arg
)) == ZLOG_DISABLED
)
1938 return CMD_ERR_NO_MATCH
;
1939 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, level
);
1943 DEFUN (no_config_log_monitor
,
1944 no_config_log_monitor_cmd
,
1945 "no log monitor [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
1948 "Disable terminal line (monitor) logging\n"
1951 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
1956 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
1960 const char *fullpath
;
1962 /* Path detection. */
1963 if (! IS_DIRECTORY_SEP (*fname
))
1965 char cwd
[MAXPATHLEN
+1];
1966 cwd
[MAXPATHLEN
] = '\0';
1968 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
1970 zlog_err ("config_log_file: Unable to alloc mem!");
1974 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
1977 zlog_err ("config_log_file: Unable to alloc mem!");
1980 sprintf (p
, "%s/%s", cwd
, fname
);
1986 ret
= zlog_set_file (NULL
, fullpath
, loglevel
);
1989 XFREE (MTYPE_TMP
, p
);
1993 vty_out (vty
, "can't open logfile %s\n", fname
);
1998 XFREE (MTYPE_HOST
, host
.logfile
);
2000 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
2002 #if defined(HAVE_CUMULUS)
2003 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
2004 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
2009 DEFUN (config_log_file
,
2010 config_log_file_cmd
,
2011 "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2014 "Logging filename\n"
2017 int idx_filename
= 2;
2018 int idx_log_levels
= 3;
2022 if ((level
= level_match(argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2023 return CMD_ERR_NO_MATCH
;
2024 return set_log_file(vty
, argv
[idx_filename
]->arg
, level
);
2027 return set_log_file(vty
, argv
[idx_filename
]->arg
, zlog_default
->default_lvl
);
2030 DEFUN (no_config_log_file
,
2031 no_config_log_file_cmd
,
2032 "no log file [FILENAME [LEVEL]]",
2035 "Cancel logging to file\n"
2036 "Logging file name\n"
2037 "Logging file name\n"
2040 zlog_reset_file (NULL
);
2043 XFREE (MTYPE_HOST
, host
.logfile
);
2045 host
.logfile
= NULL
;
2050 DEFUN (config_log_syslog
,
2051 config_log_syslog_cmd
,
2052 "log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
2054 "Set syslog logging level\n"
2057 int idx_log_levels
= 2;
2061 if ((level
= level_match (argv
[idx_log_levels
]->arg
)) == ZLOG_DISABLED
)
2062 return CMD_ERR_NO_MATCH
;
2063 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, level
);
2068 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2073 DEFUN_DEPRECATED (config_log_syslog_facility
,
2074 config_log_syslog_facility_cmd
,
2075 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
2077 "Logging goes to syslog\n"
2078 "(Deprecated) Facility parameter for syslog messages\n"
2081 int facility
= facility_match(argv
[3]->arg
);
2083 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
2084 zlog_default
->facility
= facility
;
2088 DEFUN (no_config_log_syslog
,
2089 no_config_log_syslog_cmd
,
2090 "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>]",
2093 "Cancel logging to syslog\n"
2097 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
2101 DEFUN (config_log_facility
,
2102 config_log_facility_cmd
,
2103 "log facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>",
2105 "Facility parameter for syslog messages\n"
2109 int facility
= facility_match(argv
[idx_target
]->arg
);
2111 zlog_default
->facility
= facility
;
2115 DEFUN (no_config_log_facility
,
2116 no_config_log_facility_cmd
,
2117 "no log facility [<kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>]",
2120 "Reset syslog facility to default (daemon)\n"
2123 zlog_default
->facility
= LOG_DAEMON
;
2127 DEFUN_DEPRECATED (config_log_trap
,
2128 config_log_trap_cmd
,
2129 "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>",
2131 "(Deprecated) Set logging level and default for all destinations\n"
2137 if ((new_level
= level_match(argv
[2]->arg
)) == ZLOG_DISABLED
)
2138 return CMD_ERR_NO_MATCH
;
2140 zlog_default
->default_lvl
= new_level
;
2141 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
2142 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
2143 zlog_default
->maxlvl
[i
] = new_level
;
2147 DEFUN_DEPRECATED (no_config_log_trap
,
2148 no_config_log_trap_cmd
,
2149 "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]",
2152 "Permit all logging information\n"
2155 zlog_default
->default_lvl
= LOG_DEBUG
;
2159 DEFUN (config_log_record_priority
,
2160 config_log_record_priority_cmd
,
2161 "log record-priority",
2163 "Log the priority of the message within the message\n")
2165 zlog_default
->record_priority
= 1 ;
2169 DEFUN (no_config_log_record_priority
,
2170 no_config_log_record_priority_cmd
,
2171 "no log record-priority",
2174 "Do not log the priority of the message within the message\n")
2176 zlog_default
->record_priority
= 0 ;
2180 DEFUN (config_log_timestamp_precision
,
2181 config_log_timestamp_precision_cmd
,
2182 "log timestamp precision (0-6)",
2184 "Timestamp configuration\n"
2185 "Set the timestamp precision\n"
2186 "Number of subsecond digits\n")
2189 VTY_GET_INTEGER_RANGE("Timestamp Precision",
2190 zlog_default
->timestamp_precision
, argv
[idx_number
]->arg
, 0, 6);
2194 DEFUN (no_config_log_timestamp_precision
,
2195 no_config_log_timestamp_precision_cmd
,
2196 "no log timestamp precision",
2199 "Timestamp configuration\n"
2200 "Reset the timestamp precision to the default value of 0\n")
2202 zlog_default
->timestamp_precision
= 0 ;
2207 cmd_banner_motd_file (const char *file
)
2209 int success
= CMD_SUCCESS
;
2214 rpath
= realpath (file
, p
);
2216 return CMD_ERR_NO_FILE
;
2217 in
= strstr (rpath
, SYSCONFDIR
);
2221 XFREE (MTYPE_HOST
, host
.motdfile
);
2222 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
2225 success
= CMD_WARNING
;
2230 DEFUN (banner_motd_file
,
2231 banner_motd_file_cmd
,
2232 "banner motd file FILE",
2235 "Banner from a file\n"
2239 const char *filename
= argv
[idx_file
]->arg
;
2240 int cmd
= cmd_banner_motd_file (filename
);
2242 if (cmd
== CMD_ERR_NO_FILE
)
2243 vty_out (vty
, "%s does not exist", filename
);
2244 else if (cmd
== CMD_WARNING
)
2245 vty_out (vty
, "%s must be in %s", filename
, SYSCONFDIR
);
2250 DEFUN (banner_motd_default
,
2251 banner_motd_default_cmd
,
2252 "banner motd default",
2253 "Set banner string\n"
2254 "Strings for motd\n"
2257 host
.motd
= default_motd
;
2261 DEFUN (no_banner_motd
,
2265 "Set banner string\n"
2266 "Strings for motd\n")
2270 XFREE (MTYPE_HOST
, host
.motdfile
);
2271 host
.motdfile
= NULL
;
2275 /* Set config filename. Called from vty.c */
2277 host_config_set (const char *filename
)
2280 XFREE (MTYPE_HOST
, host
.config
);
2281 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
2285 host_config_get (void)
2291 install_default (enum node_type node
)
2293 install_element (node
, &config_exit_cmd
);
2294 install_element (node
, &config_quit_cmd
);
2295 install_element (node
, &config_end_cmd
);
2296 install_element (node
, &config_help_cmd
);
2297 install_element (node
, &config_list_cmd
);
2299 install_element (node
, &config_write_cmd
);
2300 install_element (node
, &show_running_config_cmd
);
2303 /* Initialize command interface. Install basic nodes and commands.
2305 * terminal = 0 -- vtysh / no logging, no config control
2306 * terminal = 1 -- normal daemon
2307 * terminal = -1 -- watchquagga / no logging, but minimal config control */
2309 cmd_init (int terminal
)
2313 /* Allocate initial top vector of commands. */
2314 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
2316 /* Default host value settings. */
2318 host
.password
= NULL
;
2320 host
.logfile
= NULL
;
2322 host
.noconfig
= (terminal
< 0);
2324 host
.motd
= default_motd
;
2325 host
.motdfile
= NULL
;
2327 /* Install top nodes. */
2328 install_node (&view_node
, NULL
);
2329 install_node (&enable_node
, NULL
);
2330 install_node (&auth_node
, NULL
);
2331 install_node (&auth_enable_node
, NULL
);
2332 install_node (&config_node
, config_write_host
);
2334 /* Each node's basic commands. */
2335 install_element (VIEW_NODE
, &show_version_cmd
);
2338 install_element (VIEW_NODE
, &config_list_cmd
);
2339 install_element (VIEW_NODE
, &config_exit_cmd
);
2340 install_element (VIEW_NODE
, &config_quit_cmd
);
2341 install_element (VIEW_NODE
, &config_help_cmd
);
2342 install_element (VIEW_NODE
, &config_enable_cmd
);
2343 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
2344 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
2345 install_element (VIEW_NODE
, &show_logging_cmd
);
2346 install_element (VIEW_NODE
, &show_commandtree_cmd
);
2347 install_element (VIEW_NODE
, &echo_cmd
);
2352 install_element (ENABLE_NODE
, &config_end_cmd
);
2353 install_element (ENABLE_NODE
, &config_disable_cmd
);
2354 install_element (ENABLE_NODE
, &config_terminal_cmd
);
2355 install_element (ENABLE_NODE
, ©_runningconf_startupconf_cmd
);
2356 install_element (ENABLE_NODE
, &config_write_cmd
);
2357 install_element (ENABLE_NODE
, &show_running_config_cmd
);
2359 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
2363 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
2364 install_default (CONFIG_NODE
);
2367 workqueue_cmd_init ();
2370 install_element (CONFIG_NODE
, &hostname_cmd
);
2371 install_element (CONFIG_NODE
, &no_hostname_cmd
);
2375 install_element (CONFIG_NODE
, &password_cmd
);
2376 install_element (CONFIG_NODE
, &enable_password_cmd
);
2377 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
2379 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
2380 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
2381 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
2382 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
2383 install_element (CONFIG_NODE
, &config_log_file_cmd
);
2384 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
2385 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
2386 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
2387 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
2388 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
2389 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
2390 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
2391 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
2392 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
2393 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
2394 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
2395 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
2396 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
2397 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
2398 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
2399 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
2400 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
2401 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
2403 vrf_install_commands ();
2405 srandom(time(NULL
));
2409 new_cmd_token (enum cmd_token_type type
, u_char attr
, char *text
, char *desc
)
2411 struct cmd_token
*token
= XMALLOC (MTYPE_CMD_TOKENS
, sizeof (struct cmd_token
));
2422 del_cmd_token (struct cmd_token
*token
)
2427 XFREE (MTYPE_CMD_TOKENS
, token
->text
);
2429 XFREE (MTYPE_CMD_TOKENS
, token
->desc
);
2431 XFREE (MTYPE_CMD_TOKENS
, token
->arg
);
2433 XFREE (MTYPE_CMD_TOKENS
, token
);
2437 copy_cmd_token (struct cmd_token
*token
)
2439 struct cmd_token
*copy
= new_cmd_token (token
->type
, token
->attr
, NULL
, NULL
);
2440 copy
->max
= token
->max
;
2441 copy
->min
= token
->min
;
2442 copy
->text
= token
->text
? XSTRDUP (MTYPE_CMD_TOKENS
, token
->text
) : NULL
;
2443 copy
->desc
= token
->desc
? XSTRDUP (MTYPE_CMD_TOKENS
, token
->desc
) : NULL
;
2444 copy
->arg
= token
->arg
? XSTRDUP (MTYPE_CMD_TOKENS
, token
->arg
) : NULL
;
2450 del_cmd_element(struct cmd_element
*cmd
)
2453 free ((char *) cmd
->string
);
2454 free ((char *) cmd
->doc
);
2458 struct cmd_element
*
2459 copy_cmd_element(const struct cmd_element
*cmd
)
2461 struct cmd_element
*el
= XMALLOC(MTYPE_CMD_TOKENS
, sizeof (struct cmd_element
));
2462 el
->string
= cmd
->string
? XSTRDUP(MTYPE_CMD_TOKENS
, cmd
->string
) : NULL
;
2463 el
->func
= cmd
->func
;
2464 el
->doc
= cmd
->doc
? XSTRDUP(MTYPE_CMD_TOKENS
, cmd
->doc
) : NULL
;
2465 el
->daemon
= cmd
->daemon
;
2466 el
->attr
= cmd
->attr
;
2473 struct cmd_node
*cmd_node
;
2477 for (unsigned int i
= 0; i
< vector_active (cmdvec
); i
++)
2478 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
2480 // deleting the graph delets the cmd_element as well
2481 graph_delete_graph (cmd_node
->cmdgraph
);
2482 vector_free (cmd_node
->cmd_vector
);
2483 hash_clean (cmd_node
->cmd_hash
, NULL
);
2484 hash_free (cmd_node
->cmd_hash
);
2485 cmd_node
->cmd_hash
= NULL
;
2488 vector_free (cmdvec
);
2493 XFREE (MTYPE_HOST
, host
.name
);
2495 XFREE (MTYPE_HOST
, host
.password
);
2496 if (host
.password_encrypt
)
2497 XFREE (MTYPE_HOST
, host
.password_encrypt
);
2499 XFREE (MTYPE_HOST
, host
.enable
);
2500 if (host
.enable_encrypt
)
2501 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
2503 XFREE (MTYPE_HOST
, host
.logfile
);
2505 XFREE (MTYPE_HOST
, host
.motdfile
);
2507 XFREE (MTYPE_HOST
, host
.config
);