2 Command interpreter routine for virtual terminal [aka TeletYpe]
3 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4 Copyright (C) 2013 by Open Source Routing.
5 Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
7 This file is part of GNU Zebra.
9 GNU Zebra is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 2, or (at your
12 option) any later version.
14 GNU Zebra is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Zebra; see the file COPYING. If not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
29 #include <lib/version.h>
34 #include "workqueue.h"
38 DEFINE_MTYPE( LIB
, HOST
, "Host config")
39 DEFINE_MTYPE( LIB
, STRVEC
, "String vector")
40 DEFINE_MTYPE_STATIC(LIB
, CMD_TOKENS
, "Command desc")
42 /* Command vector which includes some level of command lists. Normally
43 each daemon maintains each own cmdvec. */
46 struct cmd_token token_cr
;
47 char *command_cr
= NULL
;
50 * Filter types. These tell the parser whether to allow
51 * partial matching on tokens.
60 * Command matcher result value.
69 MATCHER_EXCEED_ARGC_MAX
73 * Defines which matcher_rv values constitute
74 * an error. Should be used against matcher_rv
75 * return values to do basic error checking.
77 #define MATCHER_ERROR(matcher_rv) \
78 ( (matcher_rv) == MATCHER_INCOMPLETE \
79 || (matcher_rv) == MATCHER_NO_MATCH \
80 || (matcher_rv) == MATCHER_AMBIGUOUS \
81 || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
84 /* Host information structure. */
87 /* Standard command node structures. */
88 static struct cmd_node auth_node
=
94 static struct cmd_node view_node
=
100 static struct cmd_node auth_enable_node
=
106 static struct cmd_node enable_node
=
112 static struct cmd_node config_node
=
119 /* Default motd string. */
120 static const char *default_motd
= FRR_DEFAULT_MOTD
;
122 static const struct facility_map
{
126 } syslog_facilities
[] =
128 { LOG_KERN
, "kern", 1 },
129 { LOG_USER
, "user", 2 },
130 { LOG_MAIL
, "mail", 1 },
131 { LOG_DAEMON
, "daemon", 1 },
132 { LOG_AUTH
, "auth", 1 },
133 { LOG_SYSLOG
, "syslog", 1 },
134 { LOG_LPR
, "lpr", 2 },
135 { LOG_NEWS
, "news", 1 },
136 { LOG_UUCP
, "uucp", 2 },
137 { LOG_CRON
, "cron", 1 },
139 { LOG_FTP
, "ftp", 1 },
141 { LOG_LOCAL0
, "local0", 6 },
142 { LOG_LOCAL1
, "local1", 6 },
143 { LOG_LOCAL2
, "local2", 6 },
144 { LOG_LOCAL3
, "local3", 6 },
145 { LOG_LOCAL4
, "local4", 6 },
146 { LOG_LOCAL5
, "local5", 6 },
147 { LOG_LOCAL6
, "local6", 6 },
148 { LOG_LOCAL7
, "local7", 6 },
153 facility_name(int facility
)
155 const struct facility_map
*fm
;
157 for (fm
= syslog_facilities
; fm
->name
; fm
++)
158 if (fm
->facility
== facility
)
164 facility_match(const char *str
)
166 const struct facility_map
*fm
;
168 for (fm
= syslog_facilities
; fm
->name
; fm
++)
169 if (!strncmp(str
,fm
->name
,fm
->match
))
175 level_match(const char *s
)
179 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
180 if (!strncmp (s
, zlog_priority
[level
], 2))
182 return ZLOG_DISABLED
;
185 /* This is called from main when a daemon is invoked with -v or --version. */
187 print_version (const char *progname
)
189 printf ("%s version %s\n", progname
, FRR_VERSION
);
190 printf ("%s\n", FRR_COPYRIGHT
);
191 printf ("configured with:\n\t%s\n", FRR_CONFIG_ARGS
);
195 /* Utility function to concatenate argv argument into a single string
196 with inserting ' ' character between each argument. */
198 argv_concat (const char **argv
, int argc
, int shift
)
206 for (i
= shift
; i
< argc
; i
++)
207 len
+= strlen(argv
[i
])+1;
210 p
= str
= XMALLOC(MTYPE_TMP
, len
);
211 for (i
= shift
; i
< argc
; i
++)
214 memcpy(p
, argv
[i
], (arglen
= strlen(argv
[i
])));
223 cmd_hash_key (void *p
)
225 return (uintptr_t) p
;
229 cmd_hash_cmp (const void *a
, const void *b
)
234 /* Install top node of command vector. */
236 install_node (struct cmd_node
*node
,
237 int (*func
) (struct vty
*))
239 vector_set_index (cmdvec
, node
->node
, node
);
241 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
242 node
->cmd_hash
= hash_create (cmd_hash_key
, cmd_hash_cmp
);
245 /* Breaking up string into each command piece. I assume given
246 character is separated by a space character. Return value is a
247 vector which includes char ** data element. */
249 cmd_make_strvec (const char *string
)
251 const char *cp
, *start
;
261 /* Skip white spaces. */
262 while (isspace ((int) *cp
) && *cp
!= '\0')
265 /* Return if there is only white spaces */
269 if (*cp
== '!' || *cp
== '#')
272 /* Prepare return vector. */
273 strvec
= vector_init (VECTOR_MIN_SIZE
);
275 /* Copy each command piece and set into vector. */
279 while (!(isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n') &&
283 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
284 memcpy (token
, start
, strlen
);
285 *(token
+ strlen
) = '\0';
286 vector_set (strvec
, token
);
288 while ((isspace ((int) *cp
) || *cp
== '\n' || *cp
== '\r') &&
297 /* Free allocated string vector. */
299 cmd_free_strvec (vector v
)
307 for (i
= 0; i
< vector_active (v
); i
++)
308 if ((cp
= vector_slot (v
, i
)) != NULL
)
309 XFREE (MTYPE_STRVEC
, cp
);
315 * State structure for command format parser. Tracks
316 * parse tree position and miscellaneous state variables.
317 * Used when building a command vector from format strings.
319 struct format_parser_state
321 vector topvect
; /* Top level vector */
322 vector intvect
; /* Intermediate level vector, used when there's
323 a multiple in a keyword. */
324 vector curvect
; /* current vector where read tokens should be
327 const char *string
; /* pointer to command string, not modified */
328 const char *cp
; /* pointer in command string, moved along while
330 const char *dp
; /* pointer in description string, moved along while
333 int in_keyword
; /* flag to remember if we are in a keyword group */
334 int in_multiple
; /* flag to remember if we are in a multiple group */
335 int just_read_word
; /* flag to remember if the last thing we read was a
336 real word and not some abstract token */
340 format_parser_error(struct format_parser_state
*state
, const char *message
)
342 int offset
= state
->cp
- state
->string
+ 1;
344 fprintf(stderr
, "\nError parsing command: \"%s\"\n", state
->string
);
345 fprintf(stderr
, " %*c\n", offset
, '^');
346 fprintf(stderr
, "%s at offset %d.\n", message
, offset
);
347 fprintf(stderr
, "This is a programming error. Check your DEFUNs etc.\n");
352 * Reads out one section of a help string from state->dp.
353 * Leading whitespace is trimmed and the string is read until
354 * a newline is reached.
356 * @param[out] state format parser state
357 * @return the help string token read
360 format_parser_desc_str(struct format_parser_state
*state
)
362 const char *cp
, *start
;
371 /* Skip white spaces. */
372 while (isspace ((int) *cp
) && *cp
!= '\0')
375 /* Return if there is only white spaces */
381 while (!(*cp
== '\r' || *cp
== '\n') && *cp
!= '\0')
385 token
= XMALLOC (MTYPE_CMD_TOKENS
, strlen
+ 1);
386 memcpy (token
, start
, strlen
);
387 *(token
+ strlen
) = '\0';
395 * Transitions format parser state into keyword parsing mode.
396 * A cmd_token struct, `token`, representing this keyword token is initialized
397 * and appended to state->curvect. token->keyword is initialized as a vector of
398 * vector, a new vector is initialized and added to token->keyword, and
399 * state->curvect is set to point at this vector. When control returns to the
400 * caller newly parsed tokens will be added to this vector.
403 * state->curvect[HEAD] = new cmd_token
404 * state->curvect[HEAD]->keyword[0] = new vector
405 * state->curvect = state->curvect[HEAD]->keyword[0]
407 * @param[out] state state struct to transition
410 format_parser_begin_keyword(struct format_parser_state
*state
)
412 struct cmd_token
*token
;
415 if (state
->in_keyword
416 || state
->in_multiple
)
417 format_parser_error(state
, "Unexpected '{'");
420 state
->in_keyword
= 1;
422 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
423 token
->type
= TOKEN_KEYWORD
;
424 token
->keyword
= vector_init(VECTOR_MIN_SIZE
);
426 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
427 vector_set(token
->keyword
, keyword_vect
);
429 vector_set(state
->curvect
, token
);
430 state
->curvect
= keyword_vect
;
434 * Transitions format parser state into multiple parsing mode.
435 * A cmd_token struct, `token`, representing this multiple token is initialized
436 * and appended to state->curvect. token->multiple is initialized as a vector
437 * of cmd_token and state->curvect is set to point at token->multiple. If
438 * state->curvect != state->topvect (i.e. this multiple token is nested inside
439 * another composite token) then a pointer to state->curvect is saved in
443 * state->curvect[HEAD] = new cmd_token
444 * state->curvect[HEAD]->multiple = new vector
445 * state->intvect = state->curvect IFF nested token
446 * state->curvect = state->curvect[HEAD]->multiple
448 * @param[out] state state struct to transition
451 format_parser_begin_multiple(struct format_parser_state
*state
)
453 struct cmd_token
*token
;
455 if (state
->in_keyword
== 1)
456 format_parser_error(state
, "Keyword starting with '('");
458 if (state
->in_multiple
)
459 format_parser_error(state
, "Nested group");
462 state
->in_multiple
= 1;
463 state
->just_read_word
= 0;
465 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
466 token
->type
= TOKEN_MULTIPLE
;
467 token
->multiple
= vector_init(VECTOR_MIN_SIZE
);
469 vector_set(state
->curvect
, token
);
470 if (state
->curvect
!= state
->topvect
)
471 state
->intvect
= state
->curvect
;
472 state
->curvect
= token
->multiple
;
476 * Transition format parser state out of keyword parsing mode.
477 * This function is called upon encountering '}'.
478 * state->curvect is reassigned to the top level vector (as
479 * keywords cannot be nested) and state flags are set appropriately.
481 * @param[out] state state struct to transition
484 format_parser_end_keyword(struct format_parser_state
*state
)
486 if (state
->in_multiple
487 || !state
->in_keyword
)
488 format_parser_error(state
, "Unexpected '}'");
490 if (state
->in_keyword
== 1)
491 format_parser_error(state
, "Empty keyword group");
494 state
->in_keyword
= 0;
495 state
->curvect
= state
->topvect
;
499 * Transition format parser state out of multiple parsing mode.
500 * This function is called upon encountering ')'.
501 * state->curvect is reassigned to its parent vector (state->intvect
502 * if the multiple token being exited was nested inside another token,
503 * state->topvect otherwise) and state flags are set appropriately.
505 * @param[out] state state struct to transition
508 format_parser_end_multiple(struct format_parser_state
*state
)
512 if (!state
->in_multiple
)
513 format_parser_error(state
, "Unexpected ')'");
515 if (vector_active(state
->curvect
) == 0)
516 format_parser_error(state
, "Empty multiple section");
518 if (!state
->just_read_word
)
520 /* There are constructions like
521 * 'show ip ospf database ... (self-originate|)'
523 * The old parser reads a description string for the
524 * word '' between |) which will never match.
525 * Simulate this behvaior by dropping the next desc
526 * string in such a case. */
528 dummy
= format_parser_desc_str(state
);
529 XFREE(MTYPE_CMD_TOKENS
, dummy
);
533 state
->in_multiple
= 0;
536 state
->curvect
= state
->intvect
;
538 state
->curvect
= state
->topvect
;
542 * Format parser handler for pipe '|' character.
543 * This character separates subtokens in multiple and keyword type tokens.
544 * If the current token is a multiple keyword, the position pointer is
545 * simply moved past the pipe and state flags are set appropriately.
546 * If the current token is a keyword token, the position pointer is moved
547 * past the pipe. Then the cmd_token struct for the keyword is fetched and
548 * a new vector of cmd_token is appended to its vector of vector. Finally
549 * state->curvect is set to point at this new vector.
552 * state->curvect = state->topvect[HEAD]->keyword[HEAD] = new vector
554 * @param[out] state state struct to transition
557 format_parser_handle_pipe(struct format_parser_state
*state
)
559 struct cmd_token
*keyword_token
;
562 if (state
->in_multiple
)
564 state
->just_read_word
= 0;
567 else if (state
->in_keyword
)
569 state
->in_keyword
= 1;
572 keyword_token
= vector_slot(state
->topvect
,
573 vector_active(state
->topvect
) - 1);
574 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
575 vector_set(keyword_token
->keyword
, keyword_vect
);
576 state
->curvect
= keyword_vect
;
580 format_parser_error(state
, "Unexpected '|'");
585 * Format parser handler for terminal tokens.
586 * Parses the token, appends it to state->curvect, and sets
587 * state flags appropriately.
589 * @param[out] state state struct for current format parser state
592 format_parser_read_word(struct format_parser_state
*state
)
597 struct cmd_token
*token
;
601 while (state
->cp
[0] != '\0'
602 && !strchr("\r\n(){}|", state
->cp
[0])
603 && !isspace((int)state
->cp
[0]))
606 len
= state
->cp
- start
;
607 cmd
= XMALLOC(MTYPE_CMD_TOKENS
, len
+ 1);
608 memcpy(cmd
, start
, len
);
611 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
612 token
->type
= TOKEN_TERMINAL
;
613 if (strcmp (cmd
, "A.B.C.D") == 0)
614 token
->terminal
= TERMINAL_IPV4
;
615 else if (strcmp (cmd
, "A.B.C.D/M") == 0)
616 token
->terminal
= TERMINAL_IPV4_PREFIX
;
617 else if (strcmp (cmd
, "X:X::X:X") == 0)
618 token
->terminal
= TERMINAL_IPV6
;
619 else if (strcmp (cmd
, "X:X::X:X/M") == 0)
620 token
->terminal
= TERMINAL_IPV6_PREFIX
;
621 else if (cmd
[0] == '[')
622 token
->terminal
= TERMINAL_OPTION
;
623 else if (cmd
[0] == '.')
624 token
->terminal
= TERMINAL_VARARG
;
625 else if (cmd
[0] == '<')
626 token
->terminal
= TERMINAL_RANGE
;
627 else if (cmd
[0] >= 'A' && cmd
[0] <= 'Z')
628 token
->terminal
= TERMINAL_VARIABLE
;
630 token
->terminal
= TERMINAL_LITERAL
;
633 token
->desc
= format_parser_desc_str(state
);
634 vector_set(state
->curvect
, token
);
636 if (state
->in_keyword
== 1)
637 state
->in_keyword
= 2;
639 state
->just_read_word
= 1;
643 * Parse a given command format string and build a tree of tokens from
644 * it that is suitable to be used by the command subsystem.
646 * @param string Command format string.
647 * @param descstr Description string.
648 * @return A vector of struct cmd_token representing the given command,
652 cmd_parse_format(const char *string
, const char *descstr
)
654 struct format_parser_state state
;
659 memset(&state
, 0, sizeof(state
));
660 state
.topvect
= state
.curvect
= vector_init(VECTOR_MIN_SIZE
);
661 state
.cp
= state
.string
= string
;
666 while (isspace((int)state
.cp
[0]) && state
.cp
[0] != '\0')
673 || state
.in_multiple
)
674 format_parser_error(&state
, "Unclosed group/keyword");
675 return state
.topvect
;
677 format_parser_begin_keyword(&state
);
680 format_parser_begin_multiple(&state
);
683 format_parser_end_keyword(&state
);
686 format_parser_end_multiple(&state
);
689 format_parser_handle_pipe(&state
);
692 format_parser_read_word(&state
);
697 /* Return prompt character of specified node. */
699 cmd_prompt (enum node_type node
)
701 struct cmd_node
*cnode
;
703 cnode
= vector_slot (cmdvec
, node
);
704 return cnode
->prompt
;
707 /* Install a command into a node. */
709 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
711 struct cmd_node
*cnode
;
713 /* cmd_init hasn't been called */
716 fprintf (stderr
, "%s called before cmd_init, breakage likely\n",
721 cnode
= vector_slot (cmdvec
, ntype
);
725 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
730 if (hash_lookup (cnode
->cmd_hash
, cmd
) != NULL
)
733 "Multiple command installs to node %d of command:\n%s\n",
738 assert (hash_get (cnode
->cmd_hash
, cmd
, hash_alloc_intern
));
740 vector_set (cnode
->cmd_vector
, cmd
);
741 if (cmd
->tokens
== NULL
)
742 cmd
->tokens
= cmd_parse_format(cmd
->string
, cmd
->doc
);
744 if (ntype
== VIEW_NODE
)
745 install_element (ENABLE_NODE
, cmd
);
748 static const unsigned char itoa64
[] =
749 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
752 to64(char *s
, long v
, int n
)
756 *s
++ = itoa64
[v
&0x3f];
762 zencrypt (const char *passwd
)
766 char *crypt (const char *, const char *);
770 to64(&salt
[0], random(), 3);
771 to64(&salt
[3], tv
.tv_usec
, 3);
774 return crypt (passwd
, salt
);
777 /* This function write configuration of this host. */
779 config_write_host (struct vty
*vty
)
782 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
786 if (host
.password_encrypt
)
787 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
788 if (host
.enable_encrypt
)
789 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
794 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
796 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
799 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
801 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
803 vty_out (vty
, "log trap %s%s",
804 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
807 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
809 vty_out (vty
, "log file %s", host
.logfile
);
810 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
812 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
813 vty_out (vty
, "%s", VTY_NEWLINE
);
816 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
818 vty_out (vty
, "log stdout");
819 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
821 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
822 vty_out (vty
, "%s", VTY_NEWLINE
);
825 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
826 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
827 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
828 vty_out(vty
,"log monitor %s%s",
829 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
831 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
833 vty_out (vty
, "log syslog");
834 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
836 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
837 vty_out (vty
, "%s", VTY_NEWLINE
);
840 if (zlog_default
->facility
!= LOG_DAEMON
)
841 vty_out (vty
, "log facility %s%s",
842 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
844 if (zlog_default
->record_priority
== 1)
845 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
847 if (zlog_default
->timestamp_precision
> 0)
848 vty_out (vty
, "log timestamp precision %d%s",
849 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
852 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
855 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
858 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
862 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
863 else if (! host
.motd
)
864 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
869 /* Utility function for getting command vector. */
871 cmd_node_vector (vector v
, enum node_type ntype
)
873 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
874 return cnode
->cmd_vector
;
877 /* Completion match types. */
892 static enum match_type
893 cmd_ipv4_match (const char *str
)
896 int dots
= 0, nums
= 0;
904 memset (buf
, 0, sizeof (buf
));
913 if (*(str
+ 1) == '.')
916 if (*(str
+ 1) == '\0')
922 if (!isdigit ((int) *str
))
931 strncpy (buf
, sp
, str
- sp
);
932 if (atoi (buf
) > 255)
949 static enum match_type
950 cmd_ipv4_prefix_match (const char *str
)
961 memset (buf
, 0, sizeof (buf
));
963 while (*str
!= '\0' && *str
!= '/')
970 if (*(str
+ 1) == '.' || *(str
+ 1) == '/')
973 if (*(str
+ 1) == '\0')
980 if (!isdigit ((int) *str
))
989 strncpy (buf
, sp
, str
- sp
);
990 if (atoi (buf
) > 255)
997 if (*(str
+ 1) == '\0')
1003 else if (*str
== '\0')
1004 return partly_match
;
1008 return partly_match
;
1014 while (*str
!= '\0')
1016 if (!isdigit ((int) *str
))
1028 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
1029 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
1033 static enum match_type
1034 cmd_ipv6_match (const char *str
)
1036 struct sockaddr_in6 sin6_dummy
;
1040 return partly_match
;
1042 if (strspn (str
, IPV6_ADDR_STR
) != strlen (str
))
1045 /* use inet_pton that has a better support,
1046 * for example inet_pton can support the automatic addresses:
1049 ret
= inet_pton(AF_INET6
, str
, &sin6_dummy
.sin6_addr
);
1057 static enum match_type
1058 cmd_ipv6_prefix_match (const char *str
)
1060 struct sockaddr_in6 sin6_dummy
;
1061 const char *delim
= "/\0";
1062 char *dupe
, *prefix
, *mask
, *context
, *endptr
;
1064 enum match_type ret
;
1067 return partly_match
;
1069 if (strspn (str
, IPV6_PREFIX_STR
) != strlen (str
))
1072 /* tokenize to address + mask */
1073 dupe
= XMALLOC(MTYPE_TMP
, strlen(str
)+1);
1074 strncpy(dupe
, str
, strlen(str
)+1);
1075 prefix
= strtok_r(dupe
, delim
, &context
);
1076 mask
= strtok_r(NULL
, delim
, &context
);
1083 /* validate prefix */
1084 if (inet_pton(AF_INET6
, prefix
, &sin6_dummy
.sin6_addr
) != 1)
1089 nmask
= strtol (mask
, &endptr
, 10);
1090 if (*endptr
!= '\0' || nmask
< 0 || nmask
> 128)
1095 XFREE(MTYPE_TMP
, dupe
);
1100 #endif /* HAVE_IPV6 */
1102 #define DECIMAL_STRLEN_MAX 20
1105 cmd_range_match (const char *range
, const char *str
)
1108 char buf
[DECIMAL_STRLEN_MAX
+ 1];
1109 char *endptr
= NULL
;
1110 signed long long min
, max
, val
;
1115 val
= strtoll (str
, &endptr
, 10);
1116 if (*endptr
!= '\0')
1121 p
= strchr (range
, '-');
1124 if (p
- range
> DECIMAL_STRLEN_MAX
)
1126 strncpy (buf
, range
, p
- range
);
1127 buf
[p
- range
] = '\0';
1128 min
= strtoll (buf
, &endptr
, 10);
1129 if (*endptr
!= '\0')
1133 p
= strchr (range
, '>');
1136 if (p
- range
> DECIMAL_STRLEN_MAX
)
1138 strncpy (buf
, range
, p
- range
);
1139 buf
[p
- range
] = '\0';
1140 max
= strtoll (buf
, &endptr
, 10);
1141 if (*endptr
!= '\0')
1144 if (val
< min
|| val
> max
)
1150 static enum match_type
1151 cmd_word_match(struct cmd_token
*token
,
1152 enum filter_type filter
,
1156 enum match_type match_type
;
1160 if (filter
== FILTER_RELAXED
)
1161 if (!word
|| !strlen(word
))
1162 return partly_match
;
1167 switch (token
->terminal
)
1169 case TERMINAL_VARARG
:
1170 return vararg_match
;
1172 case TERMINAL_RANGE
:
1173 if (cmd_range_match(str
, word
))
1178 match_type
= cmd_ipv6_match(word
);
1179 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1180 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1184 case TERMINAL_IPV6_PREFIX
:
1185 match_type
= cmd_ipv6_prefix_match(word
);
1186 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1187 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1188 return ipv6_prefix_match
;
1192 match_type
= cmd_ipv4_match(word
);
1193 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1194 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1198 case TERMINAL_IPV4_PREFIX
:
1199 match_type
= cmd_ipv4_prefix_match(word
);
1200 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1201 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1202 return ipv4_prefix_match
;
1205 case TERMINAL_OPTION
:
1206 case TERMINAL_VARIABLE
:
1207 return extend_match
;
1209 case TERMINAL_LITERAL
:
1210 if (filter
== FILTER_RELAXED
&& !strncmp(str
, word
, strlen(word
)))
1212 if (!strcmp(str
, word
))
1214 return partly_match
;
1216 if (filter
== FILTER_STRICT
&& !strcmp(str
, word
))
1229 struct cmd_element
*cmd
; /* The command element the matcher is using */
1230 enum filter_type filter
; /* Whether to use strict or relaxed matching */
1231 vector vline
; /* The tokenized commandline which is to be matched */
1232 unsigned int index
; /* The index up to which matching should be done */
1234 /* If set, construct a list of matches at the position given by index */
1235 enum match_type
*match_type
;
1238 unsigned int word_index
; /* iterating over vline */
1242 push_argument(int *argc
, const char **argv
, const char *arg
)
1244 if (!arg
|| !strlen(arg
))
1250 if (*argc
>= CMD_ARGC_MAX
)
1253 argv
[(*argc
)++] = arg
;
1258 cmd_matcher_record_match(struct cmd_matcher
*matcher
,
1259 enum match_type match_type
,
1260 struct cmd_token
*token
)
1262 if (matcher
->word_index
!= matcher
->index
)
1267 if (!*matcher
->match
)
1268 *matcher
->match
= vector_init(VECTOR_MIN_SIZE
);
1269 vector_set(*matcher
->match
, token
);
1272 if (matcher
->match_type
)
1274 if (match_type
> *matcher
->match_type
)
1275 *matcher
->match_type
= match_type
;
1280 cmd_matcher_words_left(struct cmd_matcher
*matcher
)
1282 return matcher
->word_index
< vector_active(matcher
->vline
);
1286 cmd_matcher_get_word(struct cmd_matcher
*matcher
)
1288 assert(cmd_matcher_words_left(matcher
));
1290 return vector_slot(matcher
->vline
, matcher
->word_index
);
1293 static enum matcher_rv
1294 cmd_matcher_match_terminal(struct cmd_matcher
*matcher
,
1295 struct cmd_token
*token
,
1296 int *argc
, const char **argv
)
1299 enum match_type word_match
;
1301 assert(token
->type
== TOKEN_TERMINAL
);
1303 if (!cmd_matcher_words_left(matcher
))
1305 if (token
->terminal
== TERMINAL_OPTION
)
1306 return MATCHER_OK
; /* missing optional args are NOT pushed as NULL */
1308 return MATCHER_INCOMPLETE
;
1311 word
= cmd_matcher_get_word(matcher
);
1312 word_match
= cmd_word_match(token
, matcher
->filter
, word
);
1313 if (word_match
== no_match
)
1314 return MATCHER_NO_MATCH
;
1316 /* We have to record the input word as argument if it matched
1317 * against a variable. */
1318 if (TERMINAL_RECORD (token
->terminal
))
1320 if (push_argument(argc
, argv
, word
))
1321 return MATCHER_EXCEED_ARGC_MAX
;
1324 cmd_matcher_record_match(matcher
, word_match
, token
);
1326 matcher
->word_index
++;
1328 /* A vararg token should consume all left over words as arguments */
1329 if (token
->terminal
== TERMINAL_VARARG
)
1330 while (cmd_matcher_words_left(matcher
))
1332 word
= cmd_matcher_get_word(matcher
);
1333 if (word
&& strlen(word
))
1334 push_argument(argc
, argv
, word
);
1335 matcher
->word_index
++;
1341 static enum matcher_rv
1342 cmd_matcher_match_multiple(struct cmd_matcher
*matcher
,
1343 struct cmd_token
*token
,
1344 int *argc
, const char **argv
)
1346 enum match_type multiple_match
;
1347 unsigned int multiple_index
;
1349 const char *arg
= NULL
;
1350 struct cmd_token
*word_token
;
1351 enum match_type word_match
;
1353 assert(token
->type
== TOKEN_MULTIPLE
);
1355 multiple_match
= no_match
;
1357 if (!cmd_matcher_words_left(matcher
))
1358 return MATCHER_INCOMPLETE
;
1360 word
= cmd_matcher_get_word(matcher
);
1361 for (multiple_index
= 0;
1362 multiple_index
< vector_active(token
->multiple
);
1365 word_token
= vector_slot(token
->multiple
, multiple_index
);
1367 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1368 if (word_match
== no_match
)
1371 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1373 if (word_match
> multiple_match
)
1375 multiple_match
= word_match
;
1378 /* To mimic the behavior of the old command implementation, we
1379 * tolerate any ambiguities here :/ */
1382 matcher
->word_index
++;
1384 if (multiple_match
== no_match
)
1385 return MATCHER_NO_MATCH
;
1387 if (push_argument(argc
, argv
, arg
))
1388 return MATCHER_EXCEED_ARGC_MAX
;
1393 static enum matcher_rv
1394 cmd_matcher_read_keywords(struct cmd_matcher
*matcher
,
1395 struct cmd_token
*token
,
1399 unsigned long keyword_mask
;
1400 unsigned int keyword_found
;
1401 enum match_type keyword_match
;
1402 enum match_type word_match
;
1403 vector keyword_vector
;
1404 struct cmd_token
*word_token
;
1407 const char **keyword_argv
;
1408 enum matcher_rv rv
= MATCHER_OK
;
1413 if (!cmd_matcher_words_left(matcher
))
1416 word
= cmd_matcher_get_word(matcher
);
1419 keyword_match
= no_match
;
1420 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1422 if (keyword_mask
& (1 << i
))
1425 keyword_vector
= vector_slot(token
->keyword
, i
);
1426 word_token
= vector_slot(keyword_vector
, 0);
1428 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1429 if (word_match
== no_match
)
1432 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1434 if (word_match
> keyword_match
)
1436 keyword_match
= word_match
;
1439 else if (word_match
== keyword_match
)
1441 if (matcher
->word_index
!= matcher
->index
|| args_vector
)
1442 return MATCHER_AMBIGUOUS
;
1446 if (keyword_found
== (unsigned int)-1)
1447 return MATCHER_NO_MATCH
;
1449 matcher
->word_index
++;
1451 if (matcher
->word_index
> matcher
->index
)
1454 keyword_mask
|= (1 << keyword_found
);
1459 keyword_argv
= XMALLOC(MTYPE_TMP
, (CMD_ARGC_MAX
+ 1) * sizeof(char*));
1460 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1461 for (i
= 0; i
< CMD_ARGC_MAX
+ 1; i
++)
1462 keyword_argv
[i
] = (void*)-1;
1463 vector_set_index(args_vector
, keyword_found
, keyword_argv
);
1467 keyword_argv
= NULL
;
1470 keyword_vector
= vector_slot(token
->keyword
, keyword_found
);
1471 /* the keyword itself is at 0. We are only interested in the arguments,
1472 * so start counting at 1. */
1473 for (i
= 1; i
< vector_active(keyword_vector
); i
++)
1475 word_token
= vector_slot(keyword_vector
, i
);
1477 switch (word_token
->type
)
1479 case TOKEN_TERMINAL
:
1480 rv
= cmd_matcher_match_terminal(matcher
, word_token
,
1481 &keyword_argc
, keyword_argv
);
1483 case TOKEN_MULTIPLE
:
1484 rv
= cmd_matcher_match_multiple(matcher
, word_token
,
1485 &keyword_argc
, keyword_argv
);
1488 assert(!"Keywords should never be nested.");
1492 if (MATCHER_ERROR(rv
))
1495 if (matcher
->word_index
> matcher
->index
)
1502 static enum matcher_rv
1503 cmd_matcher_build_keyword_args(struct cmd_matcher
*matcher
,
1504 struct cmd_token
*token
,
1505 int *argc
, const char **argv
,
1506 vector keyword_args_vector
)
1509 const char **keyword_args
;
1510 vector keyword_vector
;
1511 struct cmd_token
*word_token
;
1517 if (keyword_args_vector
== NULL
)
1520 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1522 keyword_vector
= vector_slot(token
->keyword
, i
);
1523 keyword_args
= vector_lookup(keyword_args_vector
, i
);
1525 if (vector_active(keyword_vector
) == 1)
1527 /* this is a keyword without arguments */
1530 word_token
= vector_slot(keyword_vector
, 0);
1531 arg
= word_token
->cmd
;
1532 XFREE (MTYPE_TMP
, keyword_args
);
1539 if (push_argument(argc
, argv
, arg
))
1540 rv
= MATCHER_EXCEED_ARGC_MAX
;
1544 /* this is a keyword with arguments */
1547 /* the keyword was present, so just fill in the arguments */
1548 for (j
= 0; keyword_args
[j
] != (void*)-1; j
++)
1549 if (push_argument(argc
, argv
, keyword_args
[j
]))
1550 rv
= MATCHER_EXCEED_ARGC_MAX
;
1551 XFREE(MTYPE_TMP
, keyword_args
);
1555 /* the keyword was not present, insert NULL for the arguments
1556 * the keyword would have taken. */
1557 for (j
= 1; j
< vector_active(keyword_vector
); j
++)
1559 word_token
= vector_slot(keyword_vector
, j
);
1560 if ((word_token
->type
== TOKEN_TERMINAL
1561 && TERMINAL_RECORD (word_token
->terminal
))
1562 || word_token
->type
== TOKEN_MULTIPLE
)
1564 if (push_argument(argc
, argv
, NULL
))
1565 rv
= MATCHER_EXCEED_ARGC_MAX
;
1571 vector_free(keyword_args_vector
);
1575 static enum matcher_rv
1576 cmd_matcher_match_keyword(struct cmd_matcher
*matcher
,
1577 struct cmd_token
*token
,
1578 int *argc
, const char **argv
)
1580 vector keyword_args_vector
;
1581 enum matcher_rv reader_rv
;
1582 enum matcher_rv builder_rv
;
1584 assert(token
->type
== TOKEN_KEYWORD
);
1587 keyword_args_vector
= vector_init(VECTOR_MIN_SIZE
);
1589 keyword_args_vector
= NULL
;
1591 reader_rv
= cmd_matcher_read_keywords(matcher
, token
, keyword_args_vector
);
1592 builder_rv
= cmd_matcher_build_keyword_args(matcher
, token
, argc
,
1593 argv
, keyword_args_vector
);
1594 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1596 if (!MATCHER_ERROR(reader_rv
) && MATCHER_ERROR(builder_rv
))
1603 cmd_matcher_init(struct cmd_matcher
*matcher
,
1604 struct cmd_element
*cmd
,
1605 enum filter_type filter
,
1608 enum match_type
*match_type
,
1611 memset(matcher
, 0, sizeof(*matcher
));
1614 matcher
->filter
= filter
;
1615 matcher
->vline
= vline
;
1616 matcher
->index
= index
;
1618 matcher
->match_type
= match_type
;
1619 if (matcher
->match_type
)
1620 *matcher
->match_type
= no_match
;
1621 matcher
->match
= match
;
1623 matcher
->word_index
= 0;
1626 static enum matcher_rv
1627 cmd_element_match(struct cmd_element
*cmd_element
,
1628 enum filter_type filter
,
1631 enum match_type
*match_type
,
1636 struct cmd_matcher matcher
;
1637 unsigned int token_index
;
1638 enum matcher_rv rv
= MATCHER_OK
;
1640 cmd_matcher_init(&matcher
, cmd_element
, filter
,
1641 vline
, index
, match_type
, match
);
1646 for (token_index
= 0;
1647 token_index
< vector_active(cmd_element
->tokens
);
1650 struct cmd_token
*token
= vector_slot(cmd_element
->tokens
, token_index
);
1652 switch (token
->type
)
1654 case TOKEN_TERMINAL
:
1655 rv
= cmd_matcher_match_terminal(&matcher
, token
, argc
, argv
);
1657 case TOKEN_MULTIPLE
:
1658 rv
= cmd_matcher_match_multiple(&matcher
, token
, argc
, argv
);
1661 rv
= cmd_matcher_match_keyword(&matcher
, token
, argc
, argv
);
1664 if (MATCHER_ERROR(rv
))
1667 if (matcher
.word_index
> index
)
1671 /* return MATCHER_COMPLETE if all words were consumed */
1672 if (matcher
.word_index
>= vector_active(vline
))
1673 return MATCHER_COMPLETE
;
1675 /* return MATCHER_COMPLETE also if only an empty word is left. */
1676 if (matcher
.word_index
== vector_active(vline
) - 1
1677 && (!vector_slot(vline
, matcher
.word_index
)
1678 || !strlen((char*)vector_slot(vline
, matcher
.word_index
))))
1679 return MATCHER_COMPLETE
;
1681 return MATCHER_NO_MATCH
; /* command is too long to match */
1685 * Filter a given vector of commands against a given commandline and
1686 * calculate possible completions.
1688 * @param commands A vector of struct cmd_element*. Commands that don't
1689 * match against the given command line will be overwritten
1690 * with NULL in that vector.
1691 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1692 * determines how incomplete commands are handled, compare with
1693 * cmd_word_match for details.
1694 * @param vline A vector of char* containing the tokenized commandline.
1695 * @param index Only match up to the given token of the commandline.
1696 * @param match_type Record the type of the best match here.
1697 * @param matches Record the matches here. For each cmd_element in the commands
1698 * vector, a match vector will be created in the matches vector.
1699 * That vector will contain all struct command_token* of the
1700 * cmd_element which matched against the given vline at the given
1702 * @return A code specifying if an error occured. If all went right, it's
1706 cmd_vector_filter(vector commands
,
1707 enum filter_type filter
,
1710 enum match_type
*match_type
,
1714 struct cmd_element
*cmd_element
;
1715 enum match_type best_match
;
1716 enum match_type element_match
;
1717 enum matcher_rv matcher_rv
;
1719 best_match
= no_match
;
1720 *matches
= vector_init(VECTOR_MIN_SIZE
);
1722 for (i
= 0; i
< vector_active (commands
); i
++)
1723 if ((cmd_element
= vector_slot (commands
, i
)) != NULL
)
1725 vector_set_index(*matches
, i
, NULL
);
1726 matcher_rv
= cmd_element_match(cmd_element
, filter
,
1729 (vector
*)&vector_slot(*matches
, i
),
1731 if (MATCHER_ERROR(matcher_rv
))
1733 vector_slot(commands
, i
) = NULL
;
1734 if (matcher_rv
== MATCHER_AMBIGUOUS
)
1735 return CMD_ERR_AMBIGUOUS
;
1736 if (matcher_rv
== MATCHER_EXCEED_ARGC_MAX
)
1737 return CMD_ERR_EXEED_ARGC_MAX
;
1739 else if (element_match
> best_match
)
1741 best_match
= element_match
;
1744 *match_type
= best_match
;
1749 * Check whether a given commandline is complete if used for a specific
1752 * @param cmd_element A cmd_element against which the commandline should be
1754 * @param vline The tokenized commandline.
1755 * @return 1 if the given commandline is complete, 0 otherwise.
1758 cmd_is_complete(struct cmd_element
*cmd_element
,
1763 rv
= cmd_element_match(cmd_element
,
1768 return (rv
== MATCHER_COMPLETE
);
1772 * Parse a given commandline and construct a list of arguments for the
1773 * given command_element.
1775 * @param cmd_element The cmd_element for which we want to construct arguments.
1776 * @param vline The tokenized commandline.
1777 * @param argc Where to store the argument count.
1778 * @param argv Where to store the argument list. Should be at least
1779 * CMD_ARGC_MAX elements long.
1780 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1783 cmd_parse(struct cmd_element
*cmd_element
,
1785 int *argc
, const char **argv
)
1787 enum matcher_rv rv
= cmd_element_match(cmd_element
,
1794 case MATCHER_COMPLETE
:
1797 case MATCHER_NO_MATCH
:
1798 return CMD_ERR_NO_MATCH
;
1800 case MATCHER_AMBIGUOUS
:
1801 return CMD_ERR_AMBIGUOUS
;
1803 case MATCHER_EXCEED_ARGC_MAX
:
1804 return CMD_ERR_EXEED_ARGC_MAX
;
1807 return CMD_ERR_INCOMPLETE
;
1811 /* Check ambiguous match */
1813 is_cmd_ambiguous (vector cmd_vector
,
1814 const char *command
,
1816 enum match_type type
)
1820 const char *str
= NULL
;
1821 const char *matched
= NULL
;
1822 vector match_vector
;
1823 struct cmd_token
*cmd_token
;
1825 if (command
== NULL
)
1828 for (i
= 0; i
< vector_active (matches
); i
++)
1829 if ((match_vector
= vector_slot (matches
, i
)) != NULL
)
1833 for (j
= 0; j
< vector_active (match_vector
); j
++)
1834 if ((cmd_token
= vector_slot (match_vector
, j
)) != NULL
)
1836 enum match_type ret
;
1838 assert(cmd_token
->type
== TOKEN_TERMINAL
);
1839 if (cmd_token
->type
!= TOKEN_TERMINAL
)
1842 str
= cmd_token
->cmd
;
1847 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1848 && strcmp (command
, str
) == 0)
1852 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1853 && strncmp (command
, str
, strlen (command
)) == 0)
1855 if (matched
&& strcmp (matched
, str
) != 0)
1856 return 1; /* There is ambiguous match. */
1863 if (cmd_range_match (str
, command
))
1865 if (matched
&& strcmp (matched
, str
) != 0)
1874 if (cmd_token
->terminal
== TERMINAL_IPV6
)
1877 case ipv6_prefix_match
:
1878 if ((ret
= cmd_ipv6_prefix_match (command
)) != no_match
)
1880 if (ret
== partly_match
)
1881 return 2; /* There is incomplete match. */
1886 #endif /* HAVE_IPV6 */
1888 if (cmd_token
->terminal
== TERMINAL_IPV4
)
1891 case ipv4_prefix_match
:
1892 if ((ret
= cmd_ipv4_prefix_match (command
)) != no_match
)
1894 if (ret
== partly_match
)
1895 return 2; /* There is incomplete match. */
1901 if (TERMINAL_RECORD (cmd_token
->terminal
))
1910 vector_slot (cmd_vector
, i
) = NULL
;
1915 /* If src matches dst return dst string, otherwise return NULL */
1917 cmd_entry_function (const char *src
, struct cmd_token
*token
)
1919 const char *dst
= token
->cmd
;
1921 /* Skip variable arguments. */
1922 if (TERMINAL_RECORD (token
->terminal
))
1925 /* In case of 'command \t', given src is NULL string. */
1929 /* Matched with input string. */
1930 if (strncmp (src
, dst
, strlen (src
)) == 0)
1936 /* If src matches dst return dst string, otherwise return NULL */
1937 /* This version will return the dst string always if it is
1938 CMD_VARIABLE for '?' key processing */
1940 cmd_entry_function_desc (const char *src
, struct cmd_token
*token
)
1942 const char *dst
= token
->cmd
;
1944 switch (token
->terminal
)
1946 case TERMINAL_VARARG
:
1949 case TERMINAL_RANGE
:
1950 if (cmd_range_match (dst
, src
))
1956 if (cmd_ipv6_match (src
))
1961 case TERMINAL_IPV6_PREFIX
:
1962 if (cmd_ipv6_prefix_match (src
))
1968 if (cmd_ipv4_match (src
))
1973 case TERMINAL_IPV4_PREFIX
:
1974 if (cmd_ipv4_prefix_match (src
))
1979 /* Optional or variable commands always match on '?' */
1980 case TERMINAL_OPTION
:
1981 case TERMINAL_VARIABLE
:
1984 case TERMINAL_LITERAL
:
1985 /* In case of 'command \t', given src is NULL string. */
1989 if (strncmp (src
, dst
, strlen (src
)) == 0)
2001 * Check whether a string is already present in a vector of strings.
2002 * @param v A vector of char*.
2003 * @param str A char*.
2004 * @return 0 if str is already present in the vector, 1 otherwise.
2007 cmd_unique_string (vector v
, const char *str
)
2012 for (i
= 0; i
< vector_active (v
); i
++)
2013 if ((match
= vector_slot (v
, i
)) != NULL
)
2014 if (strcmp (match
, str
) == 0)
2020 * Check whether a struct cmd_token matching a given string is already
2021 * present in a vector of struct cmd_token.
2022 * @param v A vector of struct cmd_token*.
2023 * @param str A char* which should be searched for.
2024 * @return 0 if there is a struct cmd_token* with its cmd matching str,
2028 desc_unique_string (vector v
, const char *str
)
2031 struct cmd_token
*token
;
2033 for (i
= 0; i
< vector_active (v
); i
++)
2034 if ((token
= vector_slot (v
, i
)) != NULL
)
2035 if (strcmp (token
->cmd
, str
) == 0)
2041 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
2042 if ( first_word
!= NULL
&&
2043 node
!= AUTH_NODE
&&
2044 node
!= VIEW_NODE
&&
2045 node
!= AUTH_ENABLE_NODE
&&
2046 node
!= ENABLE_NODE
&&
2047 0 == strcmp( "do", first_word
) )
2053 cmd_matches_free(vector
*matches
)
2058 for (i
= 0; i
< vector_active(*matches
); i
++)
2059 if ((cmd_matches
= vector_slot(*matches
, i
)) != NULL
)
2060 vector_free(cmd_matches
);
2061 vector_free(*matches
);
2066 cmd_describe_cmp(const void *a
, const void *b
)
2068 const struct cmd_token
*first
= *(struct cmd_token
* const *)a
;
2069 const struct cmd_token
*second
= *(struct cmd_token
* const *)b
;
2071 return strcmp(first
->cmd
, second
->cmd
);
2075 cmd_describe_sort(vector matchvec
)
2077 qsort(matchvec
->index
, vector_active(matchvec
),
2078 sizeof(void*), cmd_describe_cmp
);
2081 /* '?' describe command support. */
2083 cmd_describe_command_real (vector vline
, struct vty
*vty
, int *status
)
2087 #define INIT_MATCHVEC_SIZE 10
2089 struct cmd_element
*cmd_element
;
2092 enum match_type match
;
2093 char *command
= NULL
;
2094 vector matches
= NULL
;
2095 vector match_vector
;
2096 uint32_t command_found
= 0;
2097 const char *last_word
;
2100 if (vector_active (vline
) == 0)
2102 *status
= CMD_ERR_NO_MATCH
;
2106 index
= vector_active (vline
) - 1;
2108 /* Make copy vector of current node's command vector. */
2109 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2111 /* Prepare match vector */
2112 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2114 /* Filter commands and build a list how they could possibly continue. */
2115 for (i
= 0; i
<= index
; i
++)
2117 command
= vector_slot (vline
, i
);
2120 cmd_matches_free(&matches
);
2122 ret
= cmd_vector_filter(cmd_vector
,
2128 if (ret
!= CMD_SUCCESS
)
2130 vector_free (cmd_vector
);
2131 vector_free (matchvec
);
2132 cmd_matches_free(&matches
);
2137 /* The last match may well be ambigious, so break here */
2141 if (match
== vararg_match
)
2143 /* We found a vararg match - so we can throw out the current matches here
2144 * and don't need to continue checking the command input */
2147 for (j
= 0; j
< vector_active (matches
); j
++)
2148 if ((match_vector
= vector_slot (matches
, j
)) != NULL
)
2149 for (k
= 0; k
< vector_active (match_vector
); k
++)
2151 struct cmd_token
*token
= vector_slot (match_vector
, k
);
2152 vector_set (matchvec
, token
);
2155 *status
= CMD_SUCCESS
;
2156 vector_set(matchvec
, &token_cr
);
2157 vector_free (cmd_vector
);
2158 cmd_matches_free(&matches
);
2159 cmd_describe_sort(matchvec
);
2163 ret
= is_cmd_ambiguous(cmd_vector
, command
, matches
, match
);
2166 vector_free (cmd_vector
);
2167 vector_free (matchvec
);
2168 cmd_matches_free(&matches
);
2169 *status
= CMD_ERR_AMBIGUOUS
;
2174 vector_free (cmd_vector
);
2175 vector_free (matchvec
);
2176 cmd_matches_free(&matches
);
2177 *status
= CMD_ERR_NO_MATCH
;
2182 /* Make description vector. */
2183 for (i
= 0; i
< vector_active (matches
); i
++) {
2184 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
&&
2185 !(cmd_element
->attr
== CMD_ATTR_DEPRECATED
||
2186 cmd_element
->attr
== CMD_ATTR_HIDDEN
))
2189 vector vline_trimmed
;
2192 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2193 if (last_word
== NULL
|| !strlen(last_word
))
2195 vline_trimmed
= vector_copy(vline
);
2196 vector_unset(vline_trimmed
, vector_active(vline_trimmed
) - 1);
2198 if (cmd_is_complete(cmd_element
, vline_trimmed
)
2199 && desc_unique_string(matchvec
, command_cr
))
2201 if (match
!= vararg_match
)
2202 vector_set(matchvec
, &token_cr
);
2205 vector_free(vline_trimmed
);
2208 match_vector
= vector_slot (matches
, i
);
2210 for (j
= 0; j
< vector_active(match_vector
); j
++)
2212 struct cmd_token
*token
= vector_slot(match_vector
, j
);
2215 string
= cmd_entry_function_desc(command
, token
);
2216 if (string
&& desc_unique_string(matchvec
, string
))
2217 vector_set(matchvec
, token
);
2223 * We can get into this situation when the command is complete
2224 * but the last part of the command is an optional piece of
2227 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2228 if (command_found
== 0 && (last_word
== NULL
|| !strlen(last_word
))) {
2229 vector_set(matchvec
, &token_cr
);
2232 vector_free (cmd_vector
);
2233 cmd_matches_free(&matches
);
2235 if (vector_slot (matchvec
, 0) == NULL
)
2237 vector_free (matchvec
);
2238 *status
= CMD_ERR_NO_MATCH
;
2242 *status
= CMD_SUCCESS
;
2243 cmd_describe_sort(matchvec
);
2248 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
2252 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2254 enum node_type onode
;
2255 vector shifted_vline
;
2259 vty
->node
= ENABLE_NODE
;
2260 /* We can try it on enable node, cos' the vty is authenticated */
2262 shifted_vline
= vector_init (vector_count(vline
));
2264 for (index
= 1; index
< vector_active (vline
); index
++)
2266 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2269 ret
= cmd_describe_command_real (shifted_vline
, vty
, status
);
2271 vector_free(shifted_vline
);
2277 return cmd_describe_command_real (vline
, vty
, status
);
2281 /* Check LCD of matched command. */
2283 cmd_lcd (char **matched
)
2291 if (matched
[0] == NULL
|| matched
[1] == NULL
)
2294 for (i
= 1; matched
[i
] != NULL
; i
++)
2296 s1
= matched
[i
- 1];
2299 for (j
= 0; (c1
= s1
[j
]) && (c2
= s2
[j
]); j
++)
2315 cmd_complete_cmp(const void *a
, const void *b
)
2317 const char *first
= *(char * const *)a
;
2318 const char *second
= *(char * const *)b
;
2329 return strcmp(first
, second
);
2333 cmd_complete_sort(vector matchvec
)
2335 qsort(matchvec
->index
, vector_active(matchvec
),
2336 sizeof(void*), cmd_complete_cmp
);
2339 /* Command line completion support. */
2341 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
, int islib
)
2344 vector cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2345 #define INIT_MATCHVEC_SIZE 10
2349 struct cmd_token
*token
;
2352 vector matches
= NULL
;
2353 vector match_vector
;
2355 if (vector_active (vline
) == 0)
2357 vector_free (cmd_vector
);
2358 *status
= CMD_ERR_NO_MATCH
;
2362 index
= vector_active (vline
) - 1;
2364 /* First, filter by command string */
2365 for (i
= 0; i
<= index
; i
++)
2367 command
= vector_slot (vline
, i
);
2368 enum match_type match
;
2372 cmd_matches_free(&matches
);
2374 /* First try completion match, if there is exactly match return 1 */
2375 ret
= cmd_vector_filter(cmd_vector
,
2381 if (ret
!= CMD_SUCCESS
)
2383 vector_free(cmd_vector
);
2384 cmd_matches_free(&matches
);
2389 /* Break here - the completion mustn't be checked to be non-ambiguous */
2393 /* If there is exact match then filter ambiguous match else check
2395 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2398 vector_free (cmd_vector
);
2399 cmd_matches_free(&matches
);
2400 *status
= CMD_ERR_AMBIGUOUS
;
2405 /* Prepare match vector. */
2406 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2408 /* Build the possible list of continuations into a list of completions */
2409 for (i
= 0; i
< vector_active (matches
); i
++)
2410 if ((match_vector
= vector_slot (matches
, i
)))
2415 for (j
= 0; j
< vector_active (match_vector
); j
++)
2416 if ((token
= vector_slot (match_vector
, j
)))
2418 string
= cmd_entry_function (vector_slot (vline
, index
),
2420 if (string
&& cmd_unique_string (matchvec
, string
))
2421 vector_set (matchvec
, (islib
!= 0 ?
2422 XSTRDUP (MTYPE_TMP
, string
) :
2423 strdup (string
) /* rl freed */));
2427 /* We don't need cmd_vector any more. */
2428 vector_free (cmd_vector
);
2429 cmd_matches_free(&matches
);
2431 /* No matched command */
2432 if (vector_slot (matchvec
, 0) == NULL
)
2434 vector_free (matchvec
);
2436 /* In case of 'command \t' pattern. Do you need '?' command at
2437 the end of the line. */
2438 if (vector_slot (vline
, index
) == '\0')
2439 *status
= CMD_ERR_NOTHING_TODO
;
2441 *status
= CMD_ERR_NO_MATCH
;
2445 /* Only one matched */
2446 if (vector_slot (matchvec
, 1) == NULL
)
2448 size_t index_size
= matchvec
->alloced
* sizeof (void *);
2449 match_str
= XMALLOC (MTYPE_TMP
, index_size
);
2450 memcpy (match_str
, matchvec
->index
, index_size
);
2451 vector_free (matchvec
);
2453 *status
= CMD_COMPLETE_FULL_MATCH
;
2456 /* Make it sure last element is NULL. */
2457 vector_set (matchvec
, NULL
);
2459 /* Check LCD of matched strings. */
2460 if (vector_slot (vline
, index
) != NULL
)
2462 lcd
= cmd_lcd ((char **) matchvec
->index
);
2466 int len
= strlen (vector_slot (vline
, index
));
2472 lcdstr
= (islib
!= 0 ?
2473 XMALLOC (MTYPE_TMP
, lcd
+ 1) :
2475 memcpy (lcdstr
, matchvec
->index
[0], lcd
);
2478 /* Free matchvec. */
2479 for (i
= 0; i
< vector_active (matchvec
); i
++)
2481 if (vector_slot (matchvec
, i
))
2484 XFREE (MTYPE_TMP
, vector_slot (matchvec
, i
));
2486 free (vector_slot (matchvec
, i
));
2489 vector_free (matchvec
);
2491 /* Make new matchvec. */
2492 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2493 vector_set (matchvec
, lcdstr
);
2495 size_t index_size
= matchvec
->alloced
* sizeof (void *);
2496 match_str
= XMALLOC (MTYPE_TMP
, index_size
);
2497 memcpy (match_str
, matchvec
->index
, index_size
);
2498 vector_free (matchvec
);
2500 *status
= CMD_COMPLETE_MATCH
;
2506 match_str
= (char **) matchvec
->index
;
2507 cmd_complete_sort(matchvec
);
2508 vector_only_wrapper_free (matchvec
);
2509 *status
= CMD_COMPLETE_LIST_MATCH
;
2514 cmd_complete_command_lib (vector vline
, struct vty
*vty
, int *status
, int islib
)
2518 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2520 enum node_type onode
;
2521 vector shifted_vline
;
2525 vty
->node
= ENABLE_NODE
;
2526 /* We can try it on enable node, cos' the vty is authenticated */
2528 shifted_vline
= vector_init (vector_count(vline
));
2530 for (index
= 1; index
< vector_active (vline
); index
++)
2532 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2535 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
, islib
);
2537 vector_free(shifted_vline
);
2542 return cmd_complete_command_real (vline
, vty
, status
, islib
);
2546 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
2548 return cmd_complete_command_lib (vline
, vty
, status
, 0);
2551 /* return parent node */
2552 /* MUST eventually converge on CONFIG_NODE */
2554 node_parent ( enum node_type node
)
2558 assert (node
> CONFIG_NODE
);
2562 case BGP_VPNV4_NODE
:
2563 case BGP_VPNV6_NODE
:
2564 case BGP_ENCAP_NODE
:
2565 case BGP_ENCAPV6_NODE
:
2566 case BGP_VNC_DEFAULTS_NODE
:
2567 case BGP_VNC_NVE_GROUP_NODE
:
2568 case BGP_VNC_L2_GROUP_NODE
:
2570 case BGP_IPV4M_NODE
:
2572 case BGP_IPV6M_NODE
:
2575 case KEYCHAIN_KEY_NODE
:
2576 ret
= KEYCHAIN_NODE
;
2578 case LINK_PARAMS_NODE
:
2579 ret
= INTERFACE_NODE
;
2585 case LDP_IPV4_IFACE_NODE
:
2586 ret
= LDP_IPV4_NODE
;
2588 case LDP_IPV6_IFACE_NODE
:
2589 ret
= LDP_IPV6_NODE
;
2591 case LDP_PSEUDOWIRE_NODE
:
2592 ret
= LDP_L2VPN_NODE
;
2602 /* Execute command by argument vline vector. */
2604 cmd_execute_command_real (vector vline
,
2605 enum filter_type filter
,
2607 struct cmd_element
**cmd
)
2612 struct cmd_element
*cmd_element
;
2613 struct cmd_element
*matched_element
;
2614 unsigned int matched_count
, incomplete_count
;
2616 const char *argv
[CMD_ARGC_MAX
];
2617 enum match_type match
= 0;
2622 /* Make copy of command elements. */
2623 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2625 for (index
= 0; index
< vector_active (vline
); index
++)
2627 command
= vector_slot (vline
, index
);
2628 ret
= cmd_vector_filter(cmd_vector
,
2634 if (ret
!= CMD_SUCCESS
)
2636 cmd_matches_free(&matches
);
2640 if (match
== vararg_match
)
2642 cmd_matches_free(&matches
);
2646 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2647 cmd_matches_free(&matches
);
2651 vector_free(cmd_vector
);
2652 return CMD_ERR_AMBIGUOUS
;
2656 vector_free(cmd_vector
);
2657 return CMD_ERR_NO_MATCH
;
2661 /* Check matched count. */
2662 matched_element
= NULL
;
2664 incomplete_count
= 0;
2666 for (i
= 0; i
< vector_active (cmd_vector
); i
++)
2667 if ((cmd_element
= vector_slot (cmd_vector
, i
)))
2669 if (cmd_is_complete(cmd_element
, vline
))
2671 matched_element
= cmd_element
;
2680 /* Finish of using cmd_vector. */
2681 vector_free (cmd_vector
);
2683 /* To execute command, matched_count must be 1. */
2684 if (matched_count
== 0)
2686 if (incomplete_count
)
2687 return CMD_ERR_INCOMPLETE
;
2689 return CMD_ERR_NO_MATCH
;
2692 if (matched_count
> 1)
2693 return CMD_ERR_AMBIGUOUS
;
2695 ret
= cmd_parse(matched_element
, vline
, &argc
, argv
);
2696 if (ret
!= CMD_SUCCESS
)
2699 /* For vtysh execution. */
2701 *cmd
= matched_element
;
2703 if (matched_element
->daemon
)
2704 return CMD_SUCCESS_DAEMON
;
2706 /* Execute matched command. */
2707 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2711 * Execute a given command, handling things like "do ..." and checking
2712 * whether the given command might apply at a parent node if doesn't
2713 * apply for the current node.
2715 * @param vline Command line input, vector of char* where each element is
2717 * @param vty The vty context in which the command should be executed.
2718 * @param cmd Pointer where the struct cmd_element of the matched command
2719 * will be stored, if any. May be set to NULL if this info is
2721 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2722 * @return The status of the command that has been executed or an error code
2723 * as to why no command could be executed.
2726 cmd_execute_command (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
,
2728 int ret
, saved_ret
, tried
= 0;
2729 enum node_type onode
, try_node
;
2731 onode
= try_node
= vty
->node
;
2733 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2735 vector shifted_vline
;
2738 vty
->node
= ENABLE_NODE
;
2739 /* We can try it on enable node, cos' the vty is authenticated */
2741 shifted_vline
= vector_init (vector_count(vline
));
2743 for (index
= 1; index
< vector_active (vline
); index
++)
2745 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2748 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
2750 vector_free(shifted_vline
);
2756 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2761 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2762 while ( ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
2763 && vty
->node
> CONFIG_NODE
)
2765 try_node
= node_parent(try_node
);
2766 vty
->node
= try_node
;
2767 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2769 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
2771 /* succesfull command, leave the node as is */
2775 /* no command succeeded, reset the vty to the original node and
2776 return the error for this node */
2783 * Execute a given command, matching it strictly against the current node.
2784 * This mode is used when reading config files.
2786 * @param vline Command line input, vector of char* where each element is
2788 * @param vty The vty context in which the command should be executed.
2789 * @param cmd Pointer where the struct cmd_element* of the matched command
2790 * will be stored, if any. May be set to NULL if this info is
2792 * @return The status of the command that has been executed or an error code
2793 * as to why no command could be executed.
2796 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
2797 struct cmd_element
**cmd
)
2799 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
2803 * Parse one line of config, walking up the parse tree attempting to find a match
2805 * @param vty The vty context in which the command should be executed.
2806 * @param cmd Pointer where the struct cmd_element* of the match command
2807 * will be stored, if any. May be set to NULL if this info is
2809 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2811 * @return The status of the command that has been executed or an error code
2812 * as to why no command could be executed.
2815 command_config_read_one_line (struct vty
*vty
, struct cmd_element
**cmd
, int use_daemon
)
2821 vline
= cmd_make_strvec (vty
->buf
);
2823 /* In case of comment line */
2827 /* Execute configuration command : this is strict match */
2828 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2830 // Climb the tree and try the command again at each node
2831 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2832 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2833 ret
!= CMD_SUCCESS
&&
2834 ret
!= CMD_WARNING
&&
2835 vty
->node
!= CONFIG_NODE
) {
2837 saved_node
= vty
->node
;
2839 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2840 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2841 ret
!= CMD_SUCCESS
&&
2842 ret
!= CMD_WARNING
&&
2843 vty
->node
> CONFIG_NODE
) {
2844 vty
->node
= node_parent(vty
->node
);
2845 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2848 // If climbing the tree did not work then ignore the command and
2849 // stay at the same node
2850 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2851 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2852 ret
!= CMD_SUCCESS
&&
2855 vty
->node
= saved_node
;
2856 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
2860 cmd_free_strvec (vline
);
2865 /* Configuration make from file. */
2867 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
2869 int ret
, error_ret
=0;
2872 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
2877 ret
= command_config_read_one_line (vty
, NULL
, 0);
2879 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
2880 ret
!= CMD_ERR_NOTHING_TODO
)
2891 /* Configuration from terminal */
2892 DEFUN (config_terminal
,
2893 config_terminal_cmd
,
2894 "configure terminal",
2895 "Configuration from vty interface\n"
2896 "Configuration terminal\n")
2898 if (vty_config_lock (vty
))
2899 vty
->node
= CONFIG_NODE
;
2902 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
2908 /* Enable command */
2912 "Turn on privileged mode command\n")
2914 /* If enable password is NULL, change to ENABLE_NODE */
2915 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
2916 vty
->type
== VTY_SHELL_SERV
)
2917 vty
->node
= ENABLE_NODE
;
2919 vty
->node
= AUTH_ENABLE_NODE
;
2924 /* Disable command */
2928 "Turn off privileged mode command\n")
2930 if (vty
->node
== ENABLE_NODE
)
2931 vty
->node
= VIEW_NODE
;
2935 /* Down vty node level. */
2939 "Exit current mode and down to previous mode\n")
2945 if (vty_shell (vty
))
2948 vty
->status
= VTY_CLOSE
;
2951 vty
->node
= ENABLE_NODE
;
2952 vty_config_unlock (vty
);
2954 case INTERFACE_NODE
:
2964 case LDP_L2VPN_NODE
:
2971 vty
->node
= CONFIG_NODE
;
2974 case BGP_IPV4M_NODE
:
2975 case BGP_VPNV4_NODE
:
2976 case BGP_VPNV6_NODE
:
2977 case BGP_ENCAP_NODE
:
2978 case BGP_ENCAPV6_NODE
:
2979 case BGP_VNC_DEFAULTS_NODE
:
2980 case BGP_VNC_NVE_GROUP_NODE
:
2981 case BGP_VNC_L2_GROUP_NODE
:
2983 case BGP_IPV6M_NODE
:
2984 vty
->node
= BGP_NODE
;
2988 vty
->node
= LDP_NODE
;
2990 case LDP_IPV4_IFACE_NODE
:
2991 vty
->node
= LDP_IPV4_NODE
;
2993 case LDP_IPV6_IFACE_NODE
:
2994 vty
->node
= LDP_IPV6_NODE
;
2996 case LDP_PSEUDOWIRE_NODE
:
2997 vty
->node
= LDP_L2VPN_NODE
;
2999 case KEYCHAIN_KEY_NODE
:
3000 vty
->node
= KEYCHAIN_NODE
;
3002 case LINK_PARAMS_NODE
:
3003 vty
->node
= INTERFACE_NODE
;
3011 /* quit is alias of exit. */
3015 "Exit current mode and down to previous mode\n")
3017 /* End of configuration. */
3021 "End current mode and change to enable mode.")
3027 /* Nothing to do. */
3030 case INTERFACE_NODE
:
3037 case BGP_ENCAP_NODE
:
3038 case BGP_ENCAPV6_NODE
:
3039 case BGP_VNC_DEFAULTS_NODE
:
3040 case BGP_VNC_NVE_GROUP_NODE
:
3041 case BGP_VNC_L2_GROUP_NODE
:
3042 case BGP_VPNV4_NODE
:
3043 case BGP_VPNV6_NODE
:
3045 case BGP_IPV4M_NODE
:
3047 case BGP_IPV6M_NODE
:
3054 case LDP_IPV4_IFACE_NODE
:
3055 case LDP_IPV6_IFACE_NODE
:
3056 case LDP_L2VPN_NODE
:
3057 case LDP_PSEUDOWIRE_NODE
:
3060 case KEYCHAIN_KEY_NODE
:
3064 case LINK_PARAMS_NODE
:
3065 vty_config_unlock (vty
);
3066 vty
->node
= ENABLE_NODE
;
3075 DEFUN (show_version
,
3079 "Displays zebra version\n")
3081 vty_out (vty
, "%s %s (%s).%s", FRR_FULL_NAME
, FRR_VERSION
,
3082 host
.name
? host
.name
: "",
3084 vty_out (vty
, "%s%s%s", FRR_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
3085 vty_out (vty
, "configured with:%s %s%s", VTY_NEWLINE
,
3086 FRR_CONFIG_ARGS
, VTY_NEWLINE
);
3091 /* Help display function for all node. */
3095 "Description of the interactive help system\n")
3098 "Quagga VTY provides advanced help feature. When you need help,%s\
3099 anytime at the command line please press '?'.%s\
3101 If nothing matches, the help list will be empty and you must backup%s\
3102 until entering a '?' shows the available options.%s\
3103 Two styles of help are provided:%s\
3104 1. Full help is available when you are ready to enter a%s\
3105 command argument (e.g. 'show ?') and describes each possible%s\
3107 2. Partial help is provided when an abbreviated argument is entered%s\
3108 and you want to know what arguments match the input%s\
3109 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3110 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3111 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
3115 /* Help display function for all node. */
3119 "Print command list\n")
3122 struct cmd_node
*cnode
= vector_slot (cmdvec
, vty
->node
);
3123 struct cmd_element
*cmd
;
3125 for (i
= 0; i
< vector_active (cnode
->cmd_vector
); i
++)
3126 if ((cmd
= vector_slot (cnode
->cmd_vector
, i
)) != NULL
3127 && !(cmd
->attr
== CMD_ATTR_DEPRECATED
3128 || cmd
->attr
== CMD_ATTR_HIDDEN
))
3129 vty_out (vty
, " %s%s", cmd
->string
,
3134 /* Write current configuration into file. */
3135 DEFUN (config_write_file
,
3136 config_write_file_cmd
,
3138 "Write running configuration to memory, network, or terminal\n"
3139 "Write to configuration file\n")
3143 struct cmd_node
*node
;
3145 char *config_file_tmp
= NULL
;
3146 char *config_file_sav
= NULL
;
3147 int ret
= CMD_WARNING
;
3148 struct vty
*file_vty
;
3149 struct stat conf_stat
;
3154 /* Check and see if we are operating under vtysh configuration */
3155 if (host
.config
== NULL
)
3157 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
3163 config_file
= host
.config
;
3166 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
3167 strcpy (config_file_sav
, config_file
);
3168 strcat (config_file_sav
, CONF_BACKUP_EXT
);
3171 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
3172 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
3174 /* Open file to configuration write. */
3175 fd
= mkstemp (config_file_tmp
);
3178 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
3183 /* Make vty for configuration file. */
3184 file_vty
= vty_new ();
3186 file_vty
->type
= VTY_FILE
;
3188 /* Config file header print. */
3189 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
3190 vty_time_print (file_vty
, 1);
3191 vty_out (file_vty
, "!\n");
3193 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3194 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3196 if ((*node
->func
) (file_vty
))
3197 vty_out (file_vty
, "!\n");
3199 vty_close (file_vty
);
3201 if (stat(config_file
, &conf_stat
) >= 0)
3203 if (unlink (config_file_sav
) != 0)
3204 if (errno
!= ENOENT
)
3206 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
3210 if (link (config_file
, config_file_sav
) != 0)
3212 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
3217 if (unlink (config_file
) != 0)
3219 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
3224 if (link (config_file_tmp
, config_file
) != 0)
3226 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
3232 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
3234 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
3235 config_file
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
3239 vty_out (vty
, "Configuration saved to %s%s", config_file
,
3244 unlink (config_file_tmp
);
3245 XFREE (MTYPE_TMP
, config_file_tmp
);
3246 XFREE (MTYPE_TMP
, config_file_sav
);
3250 ALIAS (config_write_file
,
3253 "Write running configuration to memory, network, or terminal\n")
3255 ALIAS (config_write_file
,
3256 config_write_memory_cmd
,
3258 "Write running configuration to memory, network, or terminal\n"
3259 "Write configuration to the file (same as write file)\n")
3261 ALIAS (config_write_file
,
3262 copy_runningconfig_startupconfig_cmd
,
3263 "copy running-config startup-config",
3264 "Copy configuration\n"
3265 "Copy running config to... \n"
3266 "Copy running config to startup config (same as write file)\n")
3268 /* Write current configuration into the terminal. */
3269 DEFUN (config_write_terminal
,
3270 config_write_terminal_cmd
,
3272 "Write running configuration to memory, network, or terminal\n"
3273 "Write to terminal\n")
3276 struct cmd_node
*node
;
3281 if (vty
->type
== VTY_SHELL_SERV
)
3283 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3284 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
3286 if ((*node
->func
) (vty
))
3287 vty_out (vty
, "!%s", VTY_NEWLINE
);
3292 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
3294 vty_out (vty
, "!%s", VTY_NEWLINE
);
3296 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3297 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3299 if ((*node
->func
) (vty
))
3300 vty_out (vty
, "!%s", VTY_NEWLINE
);
3302 vty_out (vty
, "end%s",VTY_NEWLINE
);
3307 /* Write current configuration into the terminal. */
3308 ALIAS (config_write_terminal
,
3309 show_running_config_cmd
,
3310 "show running-config",
3312 "running configuration\n")
3314 /* Write startup configuration into the terminal. */
3315 DEFUN (show_startup_config
,
3316 show_startup_config_cmd
,
3317 "show startup-config",
3319 "Contentes of startup configuration\n")
3326 if (host
.config
== NULL
)
3329 confp
= fopen (host
.config
, "r");
3332 vty_out (vty
, "Can't open configuration file [%s] due to '%s'%s",
3333 host
.config
, safe_strerror(errno
), VTY_NEWLINE
);
3337 while (fgets (buf
, BUFSIZ
, confp
))
3341 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
3345 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
3353 /* Hostname configuration */
3354 DEFUN (config_hostname
,
3357 "Set system's network name\n"
3358 "This system's network name\n")
3360 if (!isalpha((int) *argv
[0]))
3362 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
3367 XFREE (MTYPE_HOST
, host
.name
);
3369 host
.name
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3373 DEFUN (config_no_hostname
,
3375 "no hostname [HOSTNAME]",
3377 "Reset system's network name\n"
3378 "Host name of this router\n")
3381 XFREE (MTYPE_HOST
, host
.name
);
3386 /* VTY interface password set. */
3387 DEFUN (config_password
, password_cmd
,
3388 "password (8|) WORD",
3389 "Assign the terminal connection password\n"
3390 "Specifies a HIDDEN password will follow\n"
3392 "The HIDDEN line password string\n")
3394 /* Argument check. */
3397 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3403 if (*argv
[0] == '8')
3406 XFREE (MTYPE_HOST
, host
.password
);
3407 host
.password
= NULL
;
3408 if (host
.password_encrypt
)
3409 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3410 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3415 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3420 if (!isalnum ((int) *argv
[0]))
3423 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3428 XFREE (MTYPE_HOST
, host
.password
);
3429 host
.password
= NULL
;
3433 if (host
.password_encrypt
)
3434 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3435 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3438 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3443 ALIAS (config_password
, password_text_cmd
,
3445 "Assign the terminal connection password\n"
3446 "The UNENCRYPTED (cleartext) line password\n")
3448 /* VTY enable password set. */
3449 DEFUN (config_enable_password
, enable_password_cmd
,
3450 "enable password (8|) WORD",
3451 "Modify enable password parameters\n"
3452 "Assign the privileged level password\n"
3453 "Specifies a HIDDEN password will follow\n"
3455 "The HIDDEN 'enable' password string\n")
3457 /* Argument check. */
3460 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3464 /* Crypt type is specified. */
3467 if (*argv
[0] == '8')
3470 XFREE (MTYPE_HOST
, host
.enable
);
3473 if (host
.enable_encrypt
)
3474 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3475 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3481 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3486 if (!isalnum ((int) *argv
[0]))
3489 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3494 XFREE (MTYPE_HOST
, host
.enable
);
3497 /* Plain password input. */
3500 if (host
.enable_encrypt
)
3501 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3502 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3505 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3510 ALIAS (config_enable_password
,
3511 enable_password_text_cmd
,
3512 "enable password LINE",
3513 "Modify enable password parameters\n"
3514 "Assign the privileged level password\n"
3515 "The UNENCRYPTED (cleartext) 'enable' password\n")
3517 /* VTY enable password delete. */
3518 DEFUN (no_config_enable_password
, no_enable_password_cmd
,
3519 "no enable password",
3521 "Modify enable password parameters\n"
3522 "Assign the privileged level password\n")
3525 XFREE (MTYPE_HOST
, host
.enable
);
3528 if (host
.enable_encrypt
)
3529 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3530 host
.enable_encrypt
= NULL
;
3535 DEFUN (service_password_encrypt
,
3536 service_password_encrypt_cmd
,
3537 "service password-encryption",
3538 "Set up miscellaneous service\n"
3539 "Enable encrypted passwords\n")
3548 if (host
.password_encrypt
)
3549 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3550 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
3554 if (host
.enable_encrypt
)
3555 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3556 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
3562 DEFUN (no_service_password_encrypt
,
3563 no_service_password_encrypt_cmd
,
3564 "no service password-encryption",
3566 "Set up miscellaneous service\n"
3567 "Enable encrypted passwords\n")
3574 if (host
.password_encrypt
)
3575 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3576 host
.password_encrypt
= NULL
;
3578 if (host
.enable_encrypt
)
3579 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3580 host
.enable_encrypt
= NULL
;
3585 DEFUN (config_terminal_length
, config_terminal_length_cmd
,
3586 "terminal length <0-512>",
3587 "Set terminal line parameters\n"
3588 "Set number of lines on a screen\n"
3589 "Number of lines on screen (0 for no pausing)\n")
3592 char *endptr
= NULL
;
3594 lines
= strtol (argv
[0], &endptr
, 10);
3595 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3597 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3605 DEFUN (config_terminal_no_length
, config_terminal_no_length_cmd
,
3606 "terminal no length",
3607 "Set terminal line parameters\n"
3609 "Set number of lines on a screen\n")
3615 DEFUN (service_terminal_length
, service_terminal_length_cmd
,
3616 "service terminal-length <0-512>",
3617 "Set up miscellaneous service\n"
3618 "System wide terminal length configuration\n"
3619 "Number of lines of VTY (0 means no line control)\n")
3622 char *endptr
= NULL
;
3624 lines
= strtol (argv
[0], &endptr
, 10);
3625 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3627 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3635 DEFUN (no_service_terminal_length
, no_service_terminal_length_cmd
,
3636 "no service terminal-length [<0-512>]",
3638 "Set up miscellaneous service\n"
3639 "System wide terminal length configuration\n"
3640 "Number of lines of VTY (0 means no line control)\n")
3646 DEFUN_HIDDEN (do_echo
,
3649 "Echo a message back to the vty\n"
3650 "The message to echo\n")
3654 vty_out (vty
, "%s%s", ((message
= argv_concat(argv
, argc
, 0)) ? message
: ""),
3657 XFREE(MTYPE_TMP
, message
);
3661 DEFUN (config_logmsg
,
3663 "logmsg "LOG_LEVELS
" .MESSAGE",
3664 "Send a message to enabled logging destinations\n"
3666 "The message to send\n")
3671 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3672 return CMD_ERR_NO_MATCH
;
3674 zlog(NULL
, level
, "%s", ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
3676 XFREE(MTYPE_TMP
, message
);
3681 DEFUN (show_logging
,
3685 "Show current logging configuration\n")
3687 struct zlog
*zl
= zlog_default
;
3689 vty_out (vty
, "Syslog logging: ");
3690 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
3691 vty_out (vty
, "disabled");
3693 vty_out (vty
, "level %s, facility %s, ident %s",
3694 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
3695 facility_name(zl
->facility
), zl
->ident
);
3696 vty_out (vty
, "%s", VTY_NEWLINE
);
3698 vty_out (vty
, "Stdout logging: ");
3699 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
3700 vty_out (vty
, "disabled");
3702 vty_out (vty
, "level %s",
3703 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
3704 vty_out (vty
, "%s", VTY_NEWLINE
);
3706 vty_out (vty
, "Monitor logging: ");
3707 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
3708 vty_out (vty
, "disabled");
3710 vty_out (vty
, "level %s",
3711 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
3712 vty_out (vty
, "%s", VTY_NEWLINE
);
3714 vty_out (vty
, "File logging: ");
3715 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
3717 vty_out (vty
, "disabled");
3719 vty_out (vty
, "level %s, filename %s",
3720 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
3722 vty_out (vty
, "%s", VTY_NEWLINE
);
3724 vty_out (vty
, "Protocol name: %s%s",
3725 zlog_proto_names
[zl
->protocol
], VTY_NEWLINE
);
3726 vty_out (vty
, "Record priority: %s%s",
3727 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
3728 vty_out (vty
, "Timestamp precision: %d%s",
3729 zl
->timestamp_precision
, VTY_NEWLINE
);
3734 DEFUN (config_log_stdout
,
3735 config_log_stdout_cmd
,
3738 "Set stdout logging level\n")
3740 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
3744 DEFUN (config_log_stdout_level
,
3745 config_log_stdout_level_cmd
,
3746 "log stdout "LOG_LEVELS
,
3748 "Set stdout logging level\n"
3753 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3754 return CMD_ERR_NO_MATCH
;
3755 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, level
);
3759 DEFUN (no_config_log_stdout
,
3760 no_config_log_stdout_cmd
,
3761 "no log stdout [LEVEL]",
3764 "Cancel logging to stdout\n"
3767 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
3771 DEFUN (config_log_monitor
,
3772 config_log_monitor_cmd
,
3775 "Set terminal line (monitor) logging level\n")
3777 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
3781 DEFUN (config_log_monitor_level
,
3782 config_log_monitor_level_cmd
,
3783 "log monitor "LOG_LEVELS
,
3785 "Set terminal line (monitor) logging level\n"
3790 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3791 return CMD_ERR_NO_MATCH
;
3792 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, level
);
3796 DEFUN (no_config_log_monitor
,
3797 no_config_log_monitor_cmd
,
3798 "no log monitor [LEVEL]",
3801 "Disable terminal line (monitor) logging\n"
3804 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
3809 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
3813 const char *fullpath
;
3815 /* Path detection. */
3816 if (! IS_DIRECTORY_SEP (*fname
))
3818 char cwd
[MAXPATHLEN
+1];
3819 cwd
[MAXPATHLEN
] = '\0';
3821 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
3823 zlog_err ("config_log_file: Unable to alloc mem!");
3827 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
3830 zlog_err ("config_log_file: Unable to alloc mem!");
3833 sprintf (p
, "%s/%s", cwd
, fname
);
3839 ret
= zlog_set_file (NULL
, fullpath
, loglevel
);
3842 XFREE (MTYPE_TMP
, p
);
3846 vty_out (vty
, "can't open logfile %s\n", fname
);
3851 XFREE (MTYPE_HOST
, host
.logfile
);
3853 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
3855 #if defined(HAVE_CUMULUS)
3856 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
3857 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
3862 DEFUN (config_log_file
,
3863 config_log_file_cmd
,
3864 "log file FILENAME",
3867 "Logging filename\n")
3869 return set_log_file(vty
, argv
[0], zlog_default
->default_lvl
);
3872 DEFUN (config_log_file_level
,
3873 config_log_file_level_cmd
,
3874 "log file FILENAME "LOG_LEVELS
,
3877 "Logging filename\n"
3882 if ((level
= level_match(argv
[1])) == ZLOG_DISABLED
)
3883 return CMD_ERR_NO_MATCH
;
3884 return set_log_file(vty
, argv
[0], level
);
3887 DEFUN (no_config_log_file
,
3888 no_config_log_file_cmd
,
3889 "no log file [FILENAME]",
3892 "Cancel logging to file\n"
3893 "Logging file name\n")
3895 zlog_reset_file (NULL
);
3898 XFREE (MTYPE_HOST
, host
.logfile
);
3900 host
.logfile
= NULL
;
3905 ALIAS (no_config_log_file
,
3906 no_config_log_file_level_cmd
,
3907 "no log file FILENAME LEVEL",
3910 "Cancel logging to file\n"
3911 "Logging file name\n"
3914 DEFUN (config_log_syslog
,
3915 config_log_syslog_cmd
,
3918 "Set syslog logging level\n")
3920 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3924 DEFUN (config_log_syslog_level
,
3925 config_log_syslog_level_cmd
,
3926 "log syslog "LOG_LEVELS
,
3928 "Set syslog logging level\n"
3933 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3934 return CMD_ERR_NO_MATCH
;
3935 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, level
);
3939 DEFUN_DEPRECATED (config_log_syslog_facility
,
3940 config_log_syslog_facility_cmd
,
3941 "log syslog facility "LOG_FACILITIES
,
3943 "Logging goes to syslog\n"
3944 "(Deprecated) Facility parameter for syslog messages\n"
3949 if ((facility
= facility_match(argv
[0])) < 0)
3950 return CMD_ERR_NO_MATCH
;
3952 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3953 zlog_default
->facility
= facility
;
3957 DEFUN (no_config_log_syslog
,
3958 no_config_log_syslog_cmd
,
3959 "no log syslog [LEVEL]",
3962 "Cancel logging to syslog\n"
3965 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
3969 ALIAS (no_config_log_syslog
,
3970 no_config_log_syslog_facility_cmd
,
3971 "no log syslog facility "LOG_FACILITIES
,
3974 "Logging goes to syslog\n"
3975 "Facility parameter for syslog messages\n"
3978 DEFUN (config_log_facility
,
3979 config_log_facility_cmd
,
3980 "log facility "LOG_FACILITIES
,
3982 "Facility parameter for syslog messages\n"
3987 if ((facility
= facility_match(argv
[0])) < 0)
3988 return CMD_ERR_NO_MATCH
;
3989 zlog_default
->facility
= facility
;
3993 DEFUN (no_config_log_facility
,
3994 no_config_log_facility_cmd
,
3995 "no log facility [FACILITY]",
3998 "Reset syslog facility to default (daemon)\n"
3999 "Syslog facility\n")
4001 zlog_default
->facility
= LOG_DAEMON
;
4005 DEFUN_DEPRECATED (config_log_trap
,
4006 config_log_trap_cmd
,
4007 "log trap "LOG_LEVELS
,
4009 "(Deprecated) Set logging level and default for all destinations\n"
4015 if ((new_level
= level_match(argv
[0])) == ZLOG_DISABLED
)
4016 return CMD_ERR_NO_MATCH
;
4018 zlog_default
->default_lvl
= new_level
;
4019 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
4020 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
4021 zlog_default
->maxlvl
[i
] = new_level
;
4025 DEFUN_DEPRECATED (no_config_log_trap
,
4026 no_config_log_trap_cmd
,
4027 "no log trap [LEVEL]",
4030 "Permit all logging information\n"
4033 zlog_default
->default_lvl
= LOG_DEBUG
;
4037 DEFUN (config_log_record_priority
,
4038 config_log_record_priority_cmd
,
4039 "log record-priority",
4041 "Log the priority of the message within the message\n")
4043 zlog_default
->record_priority
= 1 ;
4047 DEFUN (no_config_log_record_priority
,
4048 no_config_log_record_priority_cmd
,
4049 "no log record-priority",
4052 "Do not log the priority of the message within the message\n")
4054 zlog_default
->record_priority
= 0 ;
4058 DEFUN (config_log_timestamp_precision
,
4059 config_log_timestamp_precision_cmd
,
4060 "log timestamp precision <0-6>",
4062 "Timestamp configuration\n"
4063 "Set the timestamp precision\n"
4064 "Number of subsecond digits\n")
4068 vty_out (vty
, "Insufficient arguments%s", VTY_NEWLINE
);
4072 VTY_GET_INTEGER_RANGE("Timestamp Precision",
4073 zlog_default
->timestamp_precision
, argv
[0], 0, 6);
4077 DEFUN (no_config_log_timestamp_precision
,
4078 no_config_log_timestamp_precision_cmd
,
4079 "no log timestamp precision",
4082 "Timestamp configuration\n"
4083 "Reset the timestamp precision to the default value of 0\n")
4085 zlog_default
->timestamp_precision
= 0 ;
4090 cmd_banner_motd_file (const char *file
)
4092 int success
= CMD_SUCCESS
;
4097 rpath
= realpath (file
, p
);
4099 return CMD_ERR_NO_FILE
;
4100 in
= strstr (rpath
, SYSCONFDIR
);
4104 XFREE (MTYPE_HOST
, host
.motdfile
);
4105 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
4108 success
= CMD_WARNING
;
4113 DEFUN (banner_motd_file
,
4114 banner_motd_file_cmd
,
4115 "banner motd file FILE",
4118 "Banner from a file\n"
4121 int cmd
= cmd_banner_motd_file (argv
[0]);
4123 if (cmd
== CMD_ERR_NO_FILE
)
4124 vty_out (vty
, "%s does not exist", argv
[0]);
4125 else if (cmd
== CMD_WARNING
)
4126 vty_out (vty
, "%s must be in %s",
4127 argv
[0], SYSCONFDIR
);
4132 DEFUN (banner_motd_default
,
4133 banner_motd_default_cmd
,
4134 "banner motd default",
4135 "Set banner string\n"
4136 "Strings for motd\n"
4139 host
.motd
= default_motd
;
4143 DEFUN (no_banner_motd
,
4147 "Set banner string\n"
4148 "Strings for motd\n")
4152 XFREE (MTYPE_HOST
, host
.motdfile
);
4153 host
.motdfile
= NULL
;
4157 DEFUN (show_commandtree
,
4158 show_commandtree_cmd
,
4161 "Show command tree\n")
4167 vty_out (vty
, "Current node id: %d%s", vty
->node
, VTY_NEWLINE
);
4169 /* vector of all commands installed at this node */
4170 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
4172 /* loop over all commands at this node */
4173 for (i
= 0; i
< vector_active(cmd_vector
); ++i
)
4175 struct cmd_element
*cmd_element
;
4177 /* A cmd_element (seems to be) is an individual command */
4178 if ((cmd_element
= vector_slot (cmd_vector
, i
)) == NULL
)
4181 vty_out (vty
, " %s%s", cmd_element
->string
, VTY_NEWLINE
);
4184 vector_free (cmd_vector
);
4188 /* Set config filename. Called from vty.c */
4190 host_config_set (const char *filename
)
4193 XFREE (MTYPE_HOST
, host
.config
);
4194 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
4198 host_config_get (void)
4204 install_default (enum node_type node
)
4206 install_element (node
, &config_exit_cmd
);
4207 install_element (node
, &config_quit_cmd
);
4208 install_element (node
, &config_end_cmd
);
4209 install_element (node
, &config_help_cmd
);
4210 install_element (node
, &config_list_cmd
);
4212 install_element (node
, &config_write_terminal_cmd
);
4213 install_element (node
, &config_write_file_cmd
);
4214 install_element (node
, &config_write_memory_cmd
);
4215 install_element (node
, &config_write_cmd
);
4216 install_element (node
, &show_running_config_cmd
);
4219 /* Initialize command interface. Install basic nodes and commands.
4221 * terminal = 0 -- vtysh / no logging, no config control
4222 * terminal = 1 -- normal daemon
4223 * terminal = -1 -- watchfrr / no logging, but minimal config control */
4225 cmd_init (int terminal
)
4229 command_cr
= XSTRDUP(MTYPE_CMD_TOKENS
, "<cr>");
4230 token_cr
.type
= TOKEN_TERMINAL
;
4231 token_cr
.terminal
= TERMINAL_LITERAL
;
4232 token_cr
.cmd
= command_cr
;
4233 token_cr
.desc
= XSTRDUP(MTYPE_CMD_TOKENS
, "");
4235 /* Allocate initial top vector of commands. */
4236 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
4238 /* Default host value settings. */
4240 host
.password
= NULL
;
4242 host
.logfile
= NULL
;
4244 host
.noconfig
= (terminal
< 0);
4246 host
.motd
= default_motd
;
4247 host
.motdfile
= NULL
;
4249 /* Install top nodes. */
4250 install_node (&view_node
, NULL
);
4251 install_node (&enable_node
, NULL
);
4252 install_node (&auth_node
, NULL
);
4253 install_node (&auth_enable_node
, NULL
);
4254 install_node (&config_node
, config_write_host
);
4256 /* Each node's basic commands. */
4257 install_element (VIEW_NODE
, &show_version_cmd
);
4260 install_element (VIEW_NODE
, &config_list_cmd
);
4261 install_element (VIEW_NODE
, &config_exit_cmd
);
4262 install_element (VIEW_NODE
, &config_quit_cmd
);
4263 install_element (VIEW_NODE
, &config_help_cmd
);
4264 install_element (VIEW_NODE
, &config_enable_cmd
);
4265 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
4266 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
4267 install_element (VIEW_NODE
, &show_logging_cmd
);
4268 install_element (VIEW_NODE
, &show_commandtree_cmd
);
4269 install_element (VIEW_NODE
, &echo_cmd
);
4274 install_element (ENABLE_NODE
, &config_end_cmd
);
4275 install_element (ENABLE_NODE
, &config_disable_cmd
);
4276 install_element (ENABLE_NODE
, &config_terminal_cmd
);
4277 install_element (ENABLE_NODE
, ©_runningconfig_startupconfig_cmd
);
4278 install_element (ENABLE_NODE
, &config_write_terminal_cmd
);
4279 install_element (ENABLE_NODE
, &config_write_file_cmd
);
4280 install_element (ENABLE_NODE
, &config_write_memory_cmd
);
4281 install_element (ENABLE_NODE
, &config_write_cmd
);
4282 install_element (ENABLE_NODE
, &show_running_config_cmd
);
4284 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
4288 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
4289 install_default (CONFIG_NODE
);
4291 install_element (VIEW_NODE
, &show_thread_cpu_cmd
);
4292 install_element (ENABLE_NODE
, &clear_thread_cpu_cmd
);
4294 install_element (VIEW_NODE
, &show_work_queues_cmd
);
4297 install_element (CONFIG_NODE
, &hostname_cmd
);
4298 install_element (CONFIG_NODE
, &no_hostname_cmd
);
4302 install_element (CONFIG_NODE
, &password_cmd
);
4303 install_element (CONFIG_NODE
, &password_text_cmd
);
4304 install_element (CONFIG_NODE
, &enable_password_cmd
);
4305 install_element (CONFIG_NODE
, &enable_password_text_cmd
);
4306 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
4308 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
4309 install_element (CONFIG_NODE
, &config_log_stdout_level_cmd
);
4310 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
4311 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
4312 install_element (CONFIG_NODE
, &config_log_monitor_level_cmd
);
4313 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
4314 install_element (CONFIG_NODE
, &config_log_file_cmd
);
4315 install_element (CONFIG_NODE
, &config_log_file_level_cmd
);
4316 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
4317 install_element (CONFIG_NODE
, &no_config_log_file_level_cmd
);
4318 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
4319 install_element (CONFIG_NODE
, &config_log_syslog_level_cmd
);
4320 install_element (CONFIG_NODE
, &config_log_syslog_facility_cmd
);
4321 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
4322 install_element (CONFIG_NODE
, &no_config_log_syslog_facility_cmd
);
4323 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
4324 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
4325 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
4326 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
4327 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
4328 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
4329 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
4330 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
4331 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
4332 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
4333 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
4334 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
4335 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
4336 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
4337 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
4339 vrf_install_commands ();
4341 srandom(time(NULL
));
4345 cmd_terminate_token(struct cmd_token
*token
)
4348 vector keyword_vect
;
4350 if (token
->multiple
)
4352 for (i
= 0; i
< vector_active(token
->multiple
); i
++)
4353 cmd_terminate_token(vector_slot(token
->multiple
, i
));
4354 vector_free(token
->multiple
);
4355 token
->multiple
= NULL
;
4360 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
4362 keyword_vect
= vector_slot(token
->keyword
, i
);
4363 for (j
= 0; j
< vector_active(keyword_vect
); j
++)
4364 cmd_terminate_token(vector_slot(keyword_vect
, j
));
4365 vector_free(keyword_vect
);
4367 vector_free(token
->keyword
);
4368 token
->keyword
= NULL
;
4371 XFREE(MTYPE_CMD_TOKENS
, token
->cmd
);
4372 XFREE(MTYPE_CMD_TOKENS
, token
->desc
);
4374 XFREE(MTYPE_CMD_TOKENS
, token
);
4378 cmd_terminate_element(struct cmd_element
*cmd
)
4382 if (cmd
->tokens
== NULL
)
4385 for (i
= 0; i
< vector_active(cmd
->tokens
); i
++)
4386 cmd_terminate_token(vector_slot(cmd
->tokens
, i
));
4388 vector_free(cmd
->tokens
);
4396 struct cmd_node
*cmd_node
;
4397 struct cmd_element
*cmd_element
;
4402 for (i
= 0; i
< vector_active (cmdvec
); i
++)
4403 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
4405 cmd_node_v
= cmd_node
->cmd_vector
;
4407 for (j
= 0; j
< vector_active (cmd_node_v
); j
++)
4408 if ((cmd_element
= vector_slot (cmd_node_v
, j
)) != NULL
)
4409 cmd_terminate_element(cmd_element
);
4411 vector_free (cmd_node_v
);
4412 hash_clean (cmd_node
->cmd_hash
, NULL
);
4413 hash_free (cmd_node
->cmd_hash
);
4414 cmd_node
->cmd_hash
= NULL
;
4417 vector_free (cmdvec
);
4422 XFREE(MTYPE_CMD_TOKENS
, command_cr
);
4424 XFREE(MTYPE_CMD_TOKENS
, token_cr
.desc
);
4426 XFREE (MTYPE_HOST
, host
.name
);
4428 XFREE (MTYPE_HOST
, host
.password
);
4429 if (host
.password_encrypt
)
4430 XFREE (MTYPE_HOST
, host
.password_encrypt
);
4432 XFREE (MTYPE_HOST
, host
.enable
);
4433 if (host
.enable_encrypt
)
4434 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
4436 XFREE (MTYPE_HOST
, host
.logfile
);
4438 XFREE (MTYPE_HOST
, host
.motdfile
);
4440 XFREE (MTYPE_HOST
, host
.config
);