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"
37 /* Command vector which includes some level of command lists. Normally
38 each daemon maintains each own cmdvec. */
41 struct cmd_token token_cr
;
42 char *command_cr
= NULL
;
45 * Filter types. These tell the parser whether to allow
46 * partial matching on tokens.
55 * Command matcher result value.
64 MATCHER_EXCEED_ARGC_MAX
68 * Defines which matcher_rv values constitute
69 * an error. Should be used against matcher_rv
70 * return values to do basic error checking.
72 #define MATCHER_ERROR(matcher_rv) \
73 ( (matcher_rv) == MATCHER_INCOMPLETE \
74 || (matcher_rv) == MATCHER_NO_MATCH \
75 || (matcher_rv) == MATCHER_AMBIGUOUS \
76 || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
79 /* Host information structure. */
82 /* Standard command node structures. */
83 static struct cmd_node auth_node
=
89 static struct cmd_node view_node
=
95 static struct cmd_node restricted_node
=
101 static struct cmd_node auth_enable_node
=
107 static struct cmd_node enable_node
=
113 static struct cmd_node config_node
=
120 /* Default motd string. */
121 static const char *default_motd
=
123 Hello, this is " QUAGGA_PROGNAME
" (version " QUAGGA_VERSION
").\r\n\
124 " QUAGGA_COPYRIGHT
"\r\n\
128 static const struct facility_map
{
132 } syslog_facilities
[] =
134 { LOG_KERN
, "kern", 1 },
135 { LOG_USER
, "user", 2 },
136 { LOG_MAIL
, "mail", 1 },
137 { LOG_DAEMON
, "daemon", 1 },
138 { LOG_AUTH
, "auth", 1 },
139 { LOG_SYSLOG
, "syslog", 1 },
140 { LOG_LPR
, "lpr", 2 },
141 { LOG_NEWS
, "news", 1 },
142 { LOG_UUCP
, "uucp", 2 },
143 { LOG_CRON
, "cron", 1 },
145 { LOG_FTP
, "ftp", 1 },
147 { LOG_LOCAL0
, "local0", 6 },
148 { LOG_LOCAL1
, "local1", 6 },
149 { LOG_LOCAL2
, "local2", 6 },
150 { LOG_LOCAL3
, "local3", 6 },
151 { LOG_LOCAL4
, "local4", 6 },
152 { LOG_LOCAL5
, "local5", 6 },
153 { LOG_LOCAL6
, "local6", 6 },
154 { LOG_LOCAL7
, "local7", 6 },
159 facility_name(int facility
)
161 const struct facility_map
*fm
;
163 for (fm
= syslog_facilities
; fm
->name
; fm
++)
164 if (fm
->facility
== facility
)
170 facility_match(const char *str
)
172 const struct facility_map
*fm
;
174 for (fm
= syslog_facilities
; fm
->name
; fm
++)
175 if (!strncmp(str
,fm
->name
,fm
->match
))
181 level_match(const char *s
)
185 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
186 if (!strncmp (s
, zlog_priority
[level
], 2))
188 return ZLOG_DISABLED
;
191 /* This is called from main when a daemon is invoked with -v or --version. */
193 print_version (const char *progname
)
195 printf ("%s version %s\n", progname
, QUAGGA_VERSION
);
196 printf ("%s\n", QUAGGA_COPYRIGHT
);
197 printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS
);
201 /* Utility function to concatenate argv argument into a single string
202 with inserting ' ' character between each argument. */
204 argv_concat (const char **argv
, int argc
, int shift
)
212 for (i
= shift
; i
< argc
; i
++)
213 len
+= strlen(argv
[i
])+1;
216 p
= str
= XMALLOC(MTYPE_TMP
, len
);
217 for (i
= shift
; i
< argc
; i
++)
220 memcpy(p
, argv
[i
], (arglen
= strlen(argv
[i
])));
228 /* Install top node of command vector. */
230 install_node (struct cmd_node
*node
,
231 int (*func
) (struct vty
*))
233 vector_set_index (cmdvec
, node
->node
, node
);
235 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
238 /* Breaking up string into each command piece. I assume given
239 character is separated by a space character. Return value is a
240 vector which includes char ** data element. */
242 cmd_make_strvec (const char *string
)
244 const char *cp
, *start
;
254 /* Skip white spaces. */
255 while (isspace ((int) *cp
) && *cp
!= '\0')
258 /* Return if there is only white spaces */
262 if (*cp
== '!' || *cp
== '#')
265 /* Prepare return vector. */
266 strvec
= vector_init (VECTOR_MIN_SIZE
);
268 /* Copy each command piece and set into vector. */
272 while (!(isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n') &&
276 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
277 memcpy (token
, start
, strlen
);
278 *(token
+ strlen
) = '\0';
279 vector_set (strvec
, token
);
281 while ((isspace ((int) *cp
) || *cp
== '\n' || *cp
== '\r') &&
290 /* Free allocated string vector. */
292 cmd_free_strvec (vector v
)
300 for (i
= 0; i
< vector_active (v
); i
++)
301 if ((cp
= vector_slot (v
, i
)) != NULL
)
302 XFREE (MTYPE_STRVEC
, cp
);
308 * State structure for command format parser. Tracks
309 * parse tree position and miscellaneous state variables.
310 * Used when building a command vector from format strings.
312 struct format_parser_state
314 vector topvect
; /* Top level vector */
315 vector intvect
; /* Intermediate level vector, used when there's
316 a multiple in a keyword. */
317 vector curvect
; /* current vector where read tokens should be
320 const char *string
; /* pointer to command string, not modified */
321 const char *cp
; /* pointer in command string, moved along while
323 const char *dp
; /* pointer in description string, moved along while
326 int in_keyword
; /* flag to remember if we are in a keyword group */
327 int in_multiple
; /* flag to remember if we are in a multiple group */
328 int just_read_word
; /* flag to remember if the last thing we read was a
329 real word and not some abstract token */
333 format_parser_error(struct format_parser_state
*state
, const char *message
)
335 int offset
= state
->cp
- state
->string
+ 1;
337 fprintf(stderr
, "\nError parsing command: \"%s\"\n", state
->string
);
338 fprintf(stderr
, " %*c\n", offset
, '^');
339 fprintf(stderr
, "%s at offset %d.\n", message
, offset
);
340 fprintf(stderr
, "This is a programming error. Check your DEFUNs etc.\n");
345 * Reads out one section of a help string from state->dp.
346 * Leading whitespace is trimmed and the string is read until
347 * a newline is reached.
349 * @param[out] state format parser state
350 * @return the help string token read
353 format_parser_desc_str(struct format_parser_state
*state
)
355 const char *cp
, *start
;
364 /* Skip white spaces. */
365 while (isspace ((int) *cp
) && *cp
!= '\0')
368 /* Return if there is only white spaces */
374 while (!(*cp
== '\r' || *cp
== '\n') && *cp
!= '\0')
378 token
= XMALLOC (MTYPE_CMD_TOKENS
, strlen
+ 1);
379 memcpy (token
, start
, strlen
);
380 *(token
+ strlen
) = '\0';
388 * Transitions format parser state into keyword parsing mode.
389 * A cmd_token struct, `token`, representing this keyword token is initialized
390 * and appended to state->curvect. token->keyword is initialized as a vector of
391 * vector, a new vector is initialized and added to token->keyword, and
392 * state->curvect is set to point at this vector. When control returns to the
393 * caller newly parsed tokens will be added to this vector.
396 * state->curvect[HEAD] = new cmd_token
397 * state->curvect[HEAD]->keyword[0] = new vector
398 * state->curvect = state->curvect[HEAD]->keyword[0]
400 * @param[out] state state struct to transition
403 format_parser_begin_keyword(struct format_parser_state
*state
)
405 struct cmd_token
*token
;
408 if (state
->in_keyword
409 || state
->in_multiple
)
410 format_parser_error(state
, "Unexpected '{'");
413 state
->in_keyword
= 1;
415 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
416 token
->type
= TOKEN_KEYWORD
;
417 token
->keyword
= vector_init(VECTOR_MIN_SIZE
);
419 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
420 vector_set(token
->keyword
, keyword_vect
);
422 vector_set(state
->curvect
, token
);
423 state
->curvect
= keyword_vect
;
427 * Transitions format parser state into multiple parsing mode.
428 * A cmd_token struct, `token`, representing this multiple token is initialized
429 * and appended to state->curvect. token->multiple is initialized as a vector
430 * of cmd_token and state->curvect is set to point at token->multiple. If
431 * state->curvect != state->topvect (i.e. this multiple token is nested inside
432 * another composite token) then a pointer to state->curvect is saved in
436 * state->curvect[HEAD] = new cmd_token
437 * state->curvect[HEAD]->multiple = new vector
438 * state->intvect = state->curvect IFF nested token
439 * state->curvect = state->curvect[HEAD]->multiple
441 * @param[out] state state struct to transition
444 format_parser_begin_multiple(struct format_parser_state
*state
)
446 struct cmd_token
*token
;
448 if (state
->in_keyword
== 1)
449 format_parser_error(state
, "Keyword starting with '('");
451 if (state
->in_multiple
)
452 format_parser_error(state
, "Nested group");
455 state
->in_multiple
= 1;
456 state
->just_read_word
= 0;
458 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
459 token
->type
= TOKEN_MULTIPLE
;
460 token
->multiple
= vector_init(VECTOR_MIN_SIZE
);
462 vector_set(state
->curvect
, token
);
463 if (state
->curvect
!= state
->topvect
)
464 state
->intvect
= state
->curvect
;
465 state
->curvect
= token
->multiple
;
469 * Transition format parser state out of keyword parsing mode.
470 * This function is called upon encountering '}'.
471 * state->curvect is reassigned to the top level vector (as
472 * keywords cannot be nested) and state flags are set appropriately.
474 * @param[out] state state struct to transition
477 format_parser_end_keyword(struct format_parser_state
*state
)
479 if (state
->in_multiple
480 || !state
->in_keyword
)
481 format_parser_error(state
, "Unexpected '}'");
483 if (state
->in_keyword
== 1)
484 format_parser_error(state
, "Empty keyword group");
487 state
->in_keyword
= 0;
488 state
->curvect
= state
->topvect
;
492 * Transition format parser state out of multiple parsing mode.
493 * This function is called upon encountering ')'.
494 * state->curvect is reassigned to its parent vector (state->intvect
495 * if the multiple token being exited was nested inside another token,
496 * state->topvect otherwise) and state flags are set appropriately.
498 * @param[out] state state struct to transition
501 format_parser_end_multiple(struct format_parser_state
*state
)
505 if (!state
->in_multiple
)
506 format_parser_error(state
, "Unexpected ')'");
508 if (vector_active(state
->curvect
) == 0)
509 format_parser_error(state
, "Empty multiple section");
511 if (!state
->just_read_word
)
513 /* There are constructions like
514 * 'show ip ospf database ... (self-originate|)'
516 * The old parser reads a description string for the
517 * word '' between |) which will never match.
518 * Simulate this behvaior by dropping the next desc
519 * string in such a case. */
521 dummy
= format_parser_desc_str(state
);
522 XFREE(MTYPE_CMD_TOKENS
, dummy
);
526 state
->in_multiple
= 0;
529 state
->curvect
= state
->intvect
;
531 state
->curvect
= state
->topvect
;
535 * Format parser handler for pipe '|' character.
536 * This character separates subtokens in multiple and keyword type tokens.
537 * If the current token is a multiple keyword, the position pointer is
538 * simply moved past the pipe and state flags are set appropriately.
539 * If the current token is a keyword token, the position pointer is moved
540 * past the pipe. Then the cmd_token struct for the keyword is fetched and
541 * a new vector of cmd_token is appended to its vector of vector. Finally
542 * state->curvect is set to point at this new vector.
545 * state->curvect = state->topvect[HEAD]->keyword[HEAD] = new vector
547 * @param[out] state state struct to transition
550 format_parser_handle_pipe(struct format_parser_state
*state
)
552 struct cmd_token
*keyword_token
;
555 if (state
->in_multiple
)
557 state
->just_read_word
= 0;
560 else if (state
->in_keyword
)
562 state
->in_keyword
= 1;
565 keyword_token
= vector_slot(state
->topvect
,
566 vector_active(state
->topvect
) - 1);
567 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
568 vector_set(keyword_token
->keyword
, keyword_vect
);
569 state
->curvect
= keyword_vect
;
573 format_parser_error(state
, "Unexpected '|'");
578 * Format parser handler for terminal tokens.
579 * Parses the token, appends it to state->curvect, and sets
580 * state flags appropriately.
582 * @param[out] state state struct for current format parser state
585 format_parser_read_word(struct format_parser_state
*state
)
590 struct cmd_token
*token
;
594 while (state
->cp
[0] != '\0'
595 && !strchr("\r\n(){}|", state
->cp
[0])
596 && !isspace((int)state
->cp
[0]))
599 len
= state
->cp
- start
;
600 cmd
= XMALLOC(MTYPE_CMD_TOKENS
, len
+ 1);
601 memcpy(cmd
, start
, len
);
604 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
605 token
->type
= TOKEN_TERMINAL
;
606 if (strcmp (cmd
, "A.B.C.D") == 0)
607 token
->terminal
= TERMINAL_IPV4
;
608 else if (strcmp (cmd
, "A.B.C.D/M") == 0)
609 token
->terminal
= TERMINAL_IPV4_PREFIX
;
610 else if (strcmp (cmd
, "X:X::X:X") == 0)
611 token
->terminal
= TERMINAL_IPV6
;
612 else if (strcmp (cmd
, "X:X::X:X/M") == 0)
613 token
->terminal
= TERMINAL_IPV6_PREFIX
;
614 else if (cmd
[0] == '[')
615 token
->terminal
= TERMINAL_OPTION
;
616 else if (cmd
[0] == '.')
617 token
->terminal
= TERMINAL_VARARG
;
618 else if (cmd
[0] == '<')
619 token
->terminal
= TERMINAL_RANGE
;
620 else if (cmd
[0] >= 'A' && cmd
[0] <= 'Z')
621 token
->terminal
= TERMINAL_VARIABLE
;
623 token
->terminal
= TERMINAL_LITERAL
;
626 token
->desc
= format_parser_desc_str(state
);
627 vector_set(state
->curvect
, token
);
629 if (state
->in_keyword
== 1)
630 state
->in_keyword
= 2;
632 state
->just_read_word
= 1;
636 * Parse a given command format string and build a tree of tokens from
637 * it that is suitable to be used by the command subsystem.
639 * @param string Command format string.
640 * @param descstr Description string.
641 * @return A vector of struct cmd_token representing the given command,
645 cmd_parse_format(const char *string
, const char *descstr
)
647 struct format_parser_state state
;
652 memset(&state
, 0, sizeof(state
));
653 state
.topvect
= state
.curvect
= vector_init(VECTOR_MIN_SIZE
);
654 state
.cp
= state
.string
= string
;
659 while (isspace((int)state
.cp
[0]) && state
.cp
[0] != '\0')
666 || state
.in_multiple
)
667 format_parser_error(&state
, "Unclosed group/keyword");
668 return state
.topvect
;
670 format_parser_begin_keyword(&state
);
673 format_parser_begin_multiple(&state
);
676 format_parser_end_keyword(&state
);
679 format_parser_end_multiple(&state
);
682 format_parser_handle_pipe(&state
);
685 format_parser_read_word(&state
);
690 /* Return prompt character of specified node. */
692 cmd_prompt (enum node_type node
)
694 struct cmd_node
*cnode
;
696 cnode
= vector_slot (cmdvec
, node
);
697 return cnode
->prompt
;
700 /* Install a command into a node. */
702 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
704 struct cmd_node
*cnode
;
706 /* cmd_init hasn't been called */
710 cnode
= vector_slot (cmdvec
, ntype
);
714 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
719 vector_set (cnode
->cmd_vector
, cmd
);
720 if (cmd
->tokens
== NULL
)
721 cmd
->tokens
= cmd_parse_format(cmd
->string
, cmd
->doc
);
724 static const unsigned char itoa64
[] =
725 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
728 to64(char *s
, long v
, int n
)
732 *s
++ = itoa64
[v
&0x3f];
738 zencrypt (const char *passwd
)
742 char *crypt (const char *, const char *);
746 to64(&salt
[0], random(), 3);
747 to64(&salt
[3], tv
.tv_usec
, 3);
750 return crypt (passwd
, salt
);
753 /* This function write configuration of this host. */
755 config_write_host (struct vty
*vty
)
758 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
762 if (host
.password_encrypt
)
763 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
764 if (host
.enable_encrypt
)
765 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
770 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
772 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
775 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
777 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
779 vty_out (vty
, "log trap %s%s",
780 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
783 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
785 vty_out (vty
, "log file %s", host
.logfile
);
786 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
788 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
789 vty_out (vty
, "%s", VTY_NEWLINE
);
792 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
794 vty_out (vty
, "log stdout");
795 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
797 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
798 vty_out (vty
, "%s", VTY_NEWLINE
);
801 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
802 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
803 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
804 vty_out(vty
,"log monitor %s%s",
805 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
807 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
809 vty_out (vty
, "log syslog");
810 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
812 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
813 vty_out (vty
, "%s", VTY_NEWLINE
);
816 if (zlog_default
->facility
!= LOG_DAEMON
)
817 vty_out (vty
, "log facility %s%s",
818 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
820 if (zlog_default
->record_priority
== 1)
821 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
823 if (zlog_default
->timestamp_precision
> 0)
824 vty_out (vty
, "log timestamp precision %d%s",
825 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
828 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
831 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
834 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
838 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
839 else if (! host
.motd
)
840 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
845 /* Utility function for getting command vector. */
847 cmd_node_vector (vector v
, enum node_type ntype
)
849 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
850 return cnode
->cmd_vector
;
853 /* Completion match types. */
868 #define IPV4_ADDR_STR "0123456789."
869 #define IPV4_PREFIX_STR "0123456789./"
872 * Determines whether a string is a valid ipv4 token.
874 * @param[in] str the string to match
875 * @return exact_match if the string is an exact match, no_match/partly_match
878 static enum match_type
879 cmd_ipv4_match (const char *str
)
881 struct sockaddr_in sin_dummy
;
886 if (strspn (str
, IPV4_ADDR_STR
) != strlen (str
))
889 if (inet_pton(AF_INET
, str
, &sin_dummy
.sin_addr
) != 1)
895 static enum match_type
896 cmd_ipv4_prefix_match (const char *str
)
898 struct sockaddr_in sin_dummy
;
899 const char *delim
= "/\0";
900 char *dupe
, *prefix
, *mask
, *context
, *endptr
;
906 if (strspn (str
, IPV4_PREFIX_STR
) != strlen (str
))
909 /* tokenize to address + mask */
910 dupe
= XMALLOC(MTYPE_TMP
, strlen(str
)+1);
911 strncpy(dupe
, str
, strlen(str
)+1);
912 prefix
= strtok_r(dupe
, delim
, &context
);
913 mask
= strtok_r(NULL
, delim
, &context
);
918 /* validate prefix */
919 if (inet_pton(AF_INET
, prefix
, &sin_dummy
.sin_addr
) != 1)
923 nmask
= strtol (mask
, &endptr
, 10);
924 if (*endptr
!= '\0' || nmask
< 0 || nmask
> 32)
927 XFREE(MTYPE_TMP
, dupe
);
932 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
933 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
937 static enum match_type
938 cmd_ipv6_match (const char *str
)
940 struct sockaddr_in6 sin6_dummy
;
946 if (strspn (str
, IPV6_ADDR_STR
) != strlen (str
))
949 /* use inet_pton that has a better support,
950 * for example inet_pton can support the automatic addresses:
953 ret
= inet_pton(AF_INET6
, str
, &sin6_dummy
.sin6_addr
);
961 static enum match_type
962 cmd_ipv6_prefix_match (const char *str
)
964 struct sockaddr_in6 sin6_dummy
;
965 const char *delim
= "/\0";
966 char *dupe
, *prefix
, *mask
, *context
, *endptr
;
972 if (strspn (str
, IPV6_PREFIX_STR
) != strlen (str
))
975 /* tokenize to address + mask */
976 dupe
= XMALLOC(MTYPE_TMP
, strlen(str
)+1);
977 strncpy(dupe
, str
, strlen(str
)+1);
978 prefix
= strtok_r(dupe
, delim
, &context
);
979 mask
= strtok_r(NULL
, delim
, &context
);
984 /* validate prefix */
985 if (inet_pton(AF_INET6
, prefix
, &sin6_dummy
.sin6_addr
) != 1)
989 nmask
= strtol (mask
, &endptr
, 10);
990 if (*endptr
!= '\0' || nmask
< 0 || nmask
> 128)
993 XFREE(MTYPE_TMP
, dupe
);
998 #endif /* HAVE_IPV6 */
1000 #define DECIMAL_STRLEN_MAX 20
1003 cmd_range_match (const char *range
, const char *str
)
1006 char buf
[DECIMAL_STRLEN_MAX
+ 1];
1007 char *endptr
= NULL
;
1008 signed long long min
, max
, val
;
1013 val
= strtoll (str
, &endptr
, 10);
1014 if (*endptr
!= '\0')
1019 p
= strchr (range
, '-');
1022 if (p
- range
> DECIMAL_STRLEN_MAX
)
1024 strncpy (buf
, range
, p
- range
);
1025 buf
[p
- range
] = '\0';
1026 min
= strtoll (buf
, &endptr
, 10);
1027 if (*endptr
!= '\0')
1031 p
= strchr (range
, '>');
1034 if (p
- range
> DECIMAL_STRLEN_MAX
)
1036 strncpy (buf
, range
, p
- range
);
1037 buf
[p
- range
] = '\0';
1038 max
= strtoll (buf
, &endptr
, 10);
1039 if (*endptr
!= '\0')
1042 if (val
< min
|| val
> max
)
1048 static enum match_type
1049 cmd_word_match(struct cmd_token
*token
,
1050 enum filter_type filter
,
1054 enum match_type match_type
;
1058 if (filter
== FILTER_RELAXED
)
1059 if (!word
|| !strlen(word
))
1060 return partly_match
;
1065 switch (token
->terminal
)
1067 case TERMINAL_VARARG
:
1068 return vararg_match
;
1070 case TERMINAL_RANGE
:
1071 if (cmd_range_match(str
, word
))
1076 match_type
= cmd_ipv6_match(word
);
1077 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1078 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1082 case TERMINAL_IPV6_PREFIX
:
1083 match_type
= cmd_ipv6_prefix_match(word
);
1084 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1085 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1086 return ipv6_prefix_match
;
1090 match_type
= cmd_ipv4_match(word
);
1091 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1092 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1096 case TERMINAL_IPV4_PREFIX
:
1097 match_type
= cmd_ipv4_prefix_match(word
);
1098 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1099 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1100 return ipv4_prefix_match
;
1103 case TERMINAL_OPTION
:
1104 case TERMINAL_VARIABLE
:
1105 return extend_match
;
1107 case TERMINAL_LITERAL
:
1108 if (filter
== FILTER_RELAXED
&& !strncmp(str
, word
, strlen(word
)))
1110 if (!strcmp(str
, word
))
1112 return partly_match
;
1114 if (filter
== FILTER_STRICT
&& !strcmp(str
, word
))
1127 struct cmd_element
*cmd
; /* The command element the matcher is using */
1128 enum filter_type filter
; /* Whether to use strict or relaxed matching */
1129 vector vline
; /* The tokenized commandline which is to be matched */
1130 unsigned int index
; /* The index up to which matching should be done */
1132 /* If set, construct a list of matches at the position given by index */
1133 enum match_type
*match_type
;
1136 unsigned int word_index
; /* iterating over vline */
1140 push_argument(int *argc
, const char **argv
, const char *arg
)
1142 if (!arg
|| !strlen(arg
))
1148 if (*argc
>= CMD_ARGC_MAX
)
1151 argv
[(*argc
)++] = arg
;
1156 cmd_matcher_record_match(struct cmd_matcher
*matcher
,
1157 enum match_type match_type
,
1158 struct cmd_token
*token
)
1160 if (matcher
->word_index
!= matcher
->index
)
1165 if (!*matcher
->match
)
1166 *matcher
->match
= vector_init(VECTOR_MIN_SIZE
);
1167 vector_set(*matcher
->match
, token
);
1170 if (matcher
->match_type
)
1172 if (match_type
> *matcher
->match_type
)
1173 *matcher
->match_type
= match_type
;
1178 cmd_matcher_words_left(struct cmd_matcher
*matcher
)
1180 return matcher
->word_index
< vector_active(matcher
->vline
);
1184 cmd_matcher_get_word(struct cmd_matcher
*matcher
)
1186 assert(cmd_matcher_words_left(matcher
));
1188 return vector_slot(matcher
->vline
, matcher
->word_index
);
1191 static enum matcher_rv
1192 cmd_matcher_match_terminal(struct cmd_matcher
*matcher
,
1193 struct cmd_token
*token
,
1194 int *argc
, const char **argv
)
1197 enum match_type word_match
;
1199 assert(token
->type
== TOKEN_TERMINAL
);
1201 if (!cmd_matcher_words_left(matcher
))
1203 if (token
->terminal
== TERMINAL_OPTION
)
1204 return MATCHER_OK
; /* missing optional args are NOT pushed as NULL */
1206 return MATCHER_INCOMPLETE
;
1209 word
= cmd_matcher_get_word(matcher
);
1210 word_match
= cmd_word_match(token
, matcher
->filter
, word
);
1211 if (word_match
== no_match
)
1212 return MATCHER_NO_MATCH
;
1214 /* We have to record the input word as argument if it matched
1215 * against a variable. */
1216 if (TERMINAL_RECORD (token
->terminal
))
1218 if (push_argument(argc
, argv
, word
))
1219 return MATCHER_EXCEED_ARGC_MAX
;
1222 cmd_matcher_record_match(matcher
, word_match
, token
);
1224 matcher
->word_index
++;
1226 /* A vararg token should consume all left over words as arguments */
1227 if (token
->terminal
== TERMINAL_VARARG
)
1228 while (cmd_matcher_words_left(matcher
))
1230 word
= cmd_matcher_get_word(matcher
);
1231 if (word
&& strlen(word
))
1232 push_argument(argc
, argv
, word
);
1233 matcher
->word_index
++;
1239 static enum matcher_rv
1240 cmd_matcher_match_multiple(struct cmd_matcher
*matcher
,
1241 struct cmd_token
*token
,
1242 int *argc
, const char **argv
)
1244 enum match_type multiple_match
;
1245 unsigned int multiple_index
;
1247 const char *arg
= NULL
;
1248 struct cmd_token
*word_token
;
1249 enum match_type word_match
;
1251 assert(token
->type
== TOKEN_MULTIPLE
);
1253 multiple_match
= no_match
;
1255 if (!cmd_matcher_words_left(matcher
))
1256 return MATCHER_INCOMPLETE
;
1258 word
= cmd_matcher_get_word(matcher
);
1259 for (multiple_index
= 0;
1260 multiple_index
< vector_active(token
->multiple
);
1263 word_token
= vector_slot(token
->multiple
, multiple_index
);
1265 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1266 if (word_match
== no_match
)
1269 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1271 if (word_match
> multiple_match
)
1273 multiple_match
= word_match
;
1276 /* To mimic the behavior of the old command implementation, we
1277 * tolerate any ambiguities here :/ */
1280 matcher
->word_index
++;
1282 if (multiple_match
== no_match
)
1283 return MATCHER_NO_MATCH
;
1285 if (push_argument(argc
, argv
, arg
))
1286 return MATCHER_EXCEED_ARGC_MAX
;
1291 static enum matcher_rv
1292 cmd_matcher_read_keywords(struct cmd_matcher
*matcher
,
1293 struct cmd_token
*token
,
1297 unsigned long keyword_mask
;
1298 unsigned int keyword_found
;
1299 enum match_type keyword_match
;
1300 enum match_type word_match
;
1301 vector keyword_vector
;
1302 struct cmd_token
*word_token
;
1305 const char **keyword_argv
;
1306 enum matcher_rv rv
= MATCHER_OK
;
1311 if (!cmd_matcher_words_left(matcher
))
1314 word
= cmd_matcher_get_word(matcher
);
1317 keyword_match
= no_match
;
1318 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1320 if (keyword_mask
& (1 << i
))
1323 keyword_vector
= vector_slot(token
->keyword
, i
);
1324 word_token
= vector_slot(keyword_vector
, 0);
1326 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1327 if (word_match
== no_match
)
1330 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1332 if (word_match
> keyword_match
)
1334 keyword_match
= word_match
;
1337 else if (word_match
== keyword_match
)
1339 if (matcher
->word_index
!= matcher
->index
|| args_vector
)
1340 return MATCHER_AMBIGUOUS
;
1344 if (keyword_found
== (unsigned int)-1)
1345 return MATCHER_NO_MATCH
;
1347 matcher
->word_index
++;
1349 if (matcher
->word_index
> matcher
->index
)
1352 keyword_mask
|= (1 << keyword_found
);
1357 keyword_argv
= XMALLOC(MTYPE_TMP
, (CMD_ARGC_MAX
+ 1) * sizeof(char*));
1358 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1359 for (i
= 0; i
< CMD_ARGC_MAX
+ 1; i
++)
1360 keyword_argv
[i
] = (void*)-1;
1361 vector_set_index(args_vector
, keyword_found
, keyword_argv
);
1365 keyword_argv
= NULL
;
1368 keyword_vector
= vector_slot(token
->keyword
, keyword_found
);
1369 /* the keyword itself is at 0. We are only interested in the arguments,
1370 * so start counting at 1. */
1371 for (i
= 1; i
< vector_active(keyword_vector
); i
++)
1373 word_token
= vector_slot(keyword_vector
, i
);
1375 switch (word_token
->type
)
1377 case TOKEN_TERMINAL
:
1378 rv
= cmd_matcher_match_terminal(matcher
, word_token
,
1379 &keyword_argc
, keyword_argv
);
1381 case TOKEN_MULTIPLE
:
1382 rv
= cmd_matcher_match_multiple(matcher
, word_token
,
1383 &keyword_argc
, keyword_argv
);
1386 assert(!"Keywords should never be nested.");
1390 if (MATCHER_ERROR(rv
))
1393 if (matcher
->word_index
> matcher
->index
)
1400 static enum matcher_rv
1401 cmd_matcher_build_keyword_args(struct cmd_matcher
*matcher
,
1402 struct cmd_token
*token
,
1403 int *argc
, const char **argv
,
1404 vector keyword_args_vector
)
1407 const char **keyword_args
;
1408 vector keyword_vector
;
1409 struct cmd_token
*word_token
;
1415 if (keyword_args_vector
== NULL
)
1418 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1420 keyword_vector
= vector_slot(token
->keyword
, i
);
1421 keyword_args
= vector_lookup(keyword_args_vector
, i
);
1423 if (vector_active(keyword_vector
) == 1)
1425 /* this is a keyword without arguments */
1428 word_token
= vector_slot(keyword_vector
, 0);
1429 arg
= word_token
->cmd
;
1436 if (push_argument(argc
, argv
, arg
))
1437 rv
= MATCHER_EXCEED_ARGC_MAX
;
1441 /* this is a keyword with arguments */
1444 /* the keyword was present, so just fill in the arguments */
1445 for (j
= 0; keyword_args
[j
] != (void*)-1; j
++)
1446 if (push_argument(argc
, argv
, keyword_args
[j
]))
1447 rv
= MATCHER_EXCEED_ARGC_MAX
;
1448 XFREE(MTYPE_TMP
, keyword_args
);
1452 /* the keyword was not present, insert NULL for the arguments
1453 * the keyword would have taken. */
1454 for (j
= 1; j
< vector_active(keyword_vector
); j
++)
1456 word_token
= vector_slot(keyword_vector
, j
);
1457 if ((word_token
->type
== TOKEN_TERMINAL
1458 && TERMINAL_RECORD (word_token
->terminal
))
1459 || word_token
->type
== TOKEN_MULTIPLE
)
1461 if (push_argument(argc
, argv
, NULL
))
1462 rv
= MATCHER_EXCEED_ARGC_MAX
;
1468 vector_free(keyword_args_vector
);
1472 static enum matcher_rv
1473 cmd_matcher_match_keyword(struct cmd_matcher
*matcher
,
1474 struct cmd_token
*token
,
1475 int *argc
, const char **argv
)
1477 vector keyword_args_vector
;
1478 enum matcher_rv reader_rv
;
1479 enum matcher_rv builder_rv
;
1481 assert(token
->type
== TOKEN_KEYWORD
);
1484 keyword_args_vector
= vector_init(VECTOR_MIN_SIZE
);
1486 keyword_args_vector
= NULL
;
1488 reader_rv
= cmd_matcher_read_keywords(matcher
, token
, keyword_args_vector
);
1489 builder_rv
= cmd_matcher_build_keyword_args(matcher
, token
, argc
,
1490 argv
, keyword_args_vector
);
1491 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1493 if (!MATCHER_ERROR(reader_rv
) && MATCHER_ERROR(builder_rv
))
1500 cmd_matcher_init(struct cmd_matcher
*matcher
,
1501 struct cmd_element
*cmd
,
1502 enum filter_type filter
,
1505 enum match_type
*match_type
,
1508 memset(matcher
, 0, sizeof(*matcher
));
1511 matcher
->filter
= filter
;
1512 matcher
->vline
= vline
;
1513 matcher
->index
= index
;
1515 matcher
->match_type
= match_type
;
1516 if (matcher
->match_type
)
1517 *matcher
->match_type
= no_match
;
1518 matcher
->match
= match
;
1520 matcher
->word_index
= 0;
1523 static enum matcher_rv
1524 cmd_element_match(struct cmd_element
*cmd_element
,
1525 enum filter_type filter
,
1528 enum match_type
*match_type
,
1533 struct cmd_matcher matcher
;
1534 unsigned int token_index
;
1535 enum matcher_rv rv
= MATCHER_OK
;
1537 cmd_matcher_init(&matcher
, cmd_element
, filter
,
1538 vline
, index
, match_type
, match
);
1543 for (token_index
= 0;
1544 token_index
< vector_active(cmd_element
->tokens
);
1547 struct cmd_token
*token
= vector_slot(cmd_element
->tokens
, token_index
);
1549 switch (token
->type
)
1551 case TOKEN_TERMINAL
:
1552 rv
= cmd_matcher_match_terminal(&matcher
, token
, argc
, argv
);
1554 case TOKEN_MULTIPLE
:
1555 rv
= cmd_matcher_match_multiple(&matcher
, token
, argc
, argv
);
1558 rv
= cmd_matcher_match_keyword(&matcher
, token
, argc
, argv
);
1561 if (MATCHER_ERROR(rv
))
1564 if (matcher
.word_index
> index
)
1568 /* return MATCHER_COMPLETE if all words were consumed */
1569 if (matcher
.word_index
>= vector_active(vline
))
1570 return MATCHER_COMPLETE
;
1572 /* return MATCHER_COMPLETE also if only an empty word is left. */
1573 if (matcher
.word_index
== vector_active(vline
) - 1
1574 && (!vector_slot(vline
, matcher
.word_index
)
1575 || !strlen((char*)vector_slot(vline
, matcher
.word_index
))))
1576 return MATCHER_COMPLETE
;
1578 return MATCHER_NO_MATCH
; /* command is too long to match */
1582 * Filter a given vector of commands against a given commandline and
1583 * calculate possible completions.
1585 * @param commands A vector of struct cmd_element*. Commands that don't
1586 * match against the given command line will be overwritten
1587 * with NULL in that vector.
1588 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1589 * determines how incomplete commands are handled, compare with
1590 * cmd_word_match for details.
1591 * @param vline A vector of char* containing the tokenized commandline.
1592 * @param index Only match up to the given token of the commandline.
1593 * @param match_type Record the type of the best match here.
1594 * @param matches Record the matches here. For each cmd_element in the commands
1595 * vector, a match vector will be created in the matches vector.
1596 * That vector will contain all struct command_token* of the
1597 * cmd_element which matched against the given vline at the given
1599 * @return A code specifying if an error occured. If all went right, it's
1603 cmd_vector_filter(vector commands
,
1604 enum filter_type filter
,
1607 enum match_type
*match_type
,
1611 struct cmd_element
*cmd_element
;
1612 enum match_type best_match
;
1613 enum match_type element_match
;
1614 enum matcher_rv matcher_rv
;
1616 best_match
= no_match
;
1617 *matches
= vector_init(VECTOR_MIN_SIZE
);
1619 for (i
= 0; i
< vector_active (commands
); i
++)
1620 if ((cmd_element
= vector_slot (commands
, i
)) != NULL
)
1622 vector_set_index(*matches
, i
, NULL
);
1623 matcher_rv
= cmd_element_match(cmd_element
, filter
,
1626 (vector
*)&vector_slot(*matches
, i
),
1628 if (MATCHER_ERROR(matcher_rv
))
1630 vector_slot(commands
, i
) = NULL
;
1631 if (matcher_rv
== MATCHER_AMBIGUOUS
)
1632 return CMD_ERR_AMBIGUOUS
;
1633 if (matcher_rv
== MATCHER_EXCEED_ARGC_MAX
)
1634 return CMD_ERR_EXEED_ARGC_MAX
;
1636 else if (element_match
> best_match
)
1638 best_match
= element_match
;
1641 *match_type
= best_match
;
1646 * Check whether a given commandline is complete if used for a specific
1649 * @param cmd_element A cmd_element against which the commandline should be
1651 * @param vline The tokenized commandline.
1652 * @return 1 if the given commandline is complete, 0 otherwise.
1655 cmd_is_complete(struct cmd_element
*cmd_element
,
1660 rv
= cmd_element_match(cmd_element
,
1665 return (rv
== MATCHER_COMPLETE
);
1669 * Parse a given commandline and construct a list of arguments for the
1670 * given command_element.
1672 * @param cmd_element The cmd_element for which we want to construct arguments.
1673 * @param vline The tokenized commandline.
1674 * @param argc Where to store the argument count.
1675 * @param argv Where to store the argument list. Should be at least
1676 * CMD_ARGC_MAX elements long.
1677 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1680 cmd_parse(struct cmd_element
*cmd_element
,
1682 int *argc
, const char **argv
)
1684 enum matcher_rv rv
= cmd_element_match(cmd_element
,
1691 case MATCHER_COMPLETE
:
1694 case MATCHER_NO_MATCH
:
1695 return CMD_ERR_NO_MATCH
;
1697 case MATCHER_AMBIGUOUS
:
1698 return CMD_ERR_AMBIGUOUS
;
1700 case MATCHER_EXCEED_ARGC_MAX
:
1701 return CMD_ERR_EXEED_ARGC_MAX
;
1704 return CMD_ERR_INCOMPLETE
;
1708 /* Check ambiguous match */
1710 is_cmd_ambiguous (vector cmd_vector
,
1711 const char *command
,
1713 enum match_type type
)
1717 const char *str
= NULL
;
1718 const char *matched
= NULL
;
1719 vector match_vector
;
1720 struct cmd_token
*cmd_token
;
1722 if (command
== NULL
)
1725 for (i
= 0; i
< vector_active (matches
); i
++)
1726 if ((match_vector
= vector_slot (matches
, i
)) != NULL
)
1730 for (j
= 0; j
< vector_active (match_vector
); j
++)
1731 if ((cmd_token
= vector_slot (match_vector
, j
)) != NULL
)
1733 enum match_type ret
;
1735 assert(cmd_token
->type
== TOKEN_TERMINAL
);
1736 if (cmd_token
->type
!= TOKEN_TERMINAL
)
1739 str
= cmd_token
->cmd
;
1744 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1745 && strcmp (command
, str
) == 0)
1749 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1750 && strncmp (command
, str
, strlen (command
)) == 0)
1752 if (matched
&& strcmp (matched
, str
) != 0)
1753 return 1; /* There is ambiguous match. */
1760 if (cmd_range_match (str
, command
))
1762 if (matched
&& strcmp (matched
, str
) != 0)
1771 if (cmd_token
->terminal
== TERMINAL_IPV6
)
1774 case ipv6_prefix_match
:
1775 if ((ret
= cmd_ipv6_prefix_match (command
)) != no_match
)
1777 if (ret
== partly_match
)
1778 return 2; /* There is incomplete match. */
1783 #endif /* HAVE_IPV6 */
1785 if (cmd_token
->terminal
== TERMINAL_IPV4
)
1788 case ipv4_prefix_match
:
1789 if ((ret
= cmd_ipv4_prefix_match (command
)) != no_match
)
1791 if (ret
== partly_match
)
1792 return 2; /* There is incomplete match. */
1798 if (TERMINAL_RECORD (cmd_token
->terminal
))
1807 vector_slot (cmd_vector
, i
) = NULL
;
1812 /* If src matches dst return dst string, otherwise return NULL */
1814 cmd_entry_function (const char *src
, struct cmd_token
*token
)
1816 const char *dst
= token
->cmd
;
1818 /* Skip variable arguments. */
1819 if (TERMINAL_RECORD (token
->terminal
))
1822 /* In case of 'command \t', given src is NULL string. */
1826 /* Matched with input string. */
1827 if (strncmp (src
, dst
, strlen (src
)) == 0)
1833 /* If src matches dst return dst string, otherwise return NULL */
1834 /* This version will return the dst string always if it is
1835 CMD_VARIABLE for '?' key processing */
1837 cmd_entry_function_desc (const char *src
, struct cmd_token
*token
)
1839 const char *dst
= token
->cmd
;
1841 switch (token
->terminal
)
1843 case TERMINAL_VARARG
:
1846 case TERMINAL_RANGE
:
1847 if (cmd_range_match (dst
, src
))
1853 if (cmd_ipv6_match (src
))
1858 case TERMINAL_IPV6_PREFIX
:
1859 if (cmd_ipv6_prefix_match (src
))
1865 if (cmd_ipv4_match (src
))
1870 case TERMINAL_IPV4_PREFIX
:
1871 if (cmd_ipv4_prefix_match (src
))
1876 /* Optional or variable commands always match on '?' */
1877 case TERMINAL_OPTION
:
1878 case TERMINAL_VARIABLE
:
1881 case TERMINAL_LITERAL
:
1882 /* In case of 'command \t', given src is NULL string. */
1886 if (strncmp (src
, dst
, strlen (src
)) == 0)
1898 * Check whether a string is already present in a vector of strings.
1899 * @param v A vector of char*.
1900 * @param str A char*.
1901 * @return 0 if str is already present in the vector, 1 otherwise.
1904 cmd_unique_string (vector v
, const char *str
)
1909 for (i
= 0; i
< vector_active (v
); i
++)
1910 if ((match
= vector_slot (v
, i
)) != NULL
)
1911 if (strcmp (match
, str
) == 0)
1917 * Check whether a struct cmd_token matching a given string is already
1918 * present in a vector of struct cmd_token.
1919 * @param v A vector of struct cmd_token*.
1920 * @param str A char* which should be searched for.
1921 * @return 0 if there is a struct cmd_token* with its cmd matching str,
1925 desc_unique_string (vector v
, const char *str
)
1928 struct cmd_token
*token
;
1930 for (i
= 0; i
< vector_active (v
); i
++)
1931 if ((token
= vector_slot (v
, i
)) != NULL
)
1932 if (strcmp (token
->cmd
, str
) == 0)
1938 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
1939 if ( first_word
!= NULL
&&
1940 node
!= AUTH_NODE
&&
1941 node
!= VIEW_NODE
&&
1942 node
!= AUTH_ENABLE_NODE
&&
1943 node
!= ENABLE_NODE
&&
1944 node
!= RESTRICTED_NODE
&&
1945 0 == strcmp( "do", first_word
) )
1951 cmd_matches_free(vector
*matches
)
1956 for (i
= 0; i
< vector_active(*matches
); i
++)
1957 if ((cmd_matches
= vector_slot(*matches
, i
)) != NULL
)
1958 vector_free(cmd_matches
);
1959 vector_free(*matches
);
1964 cmd_describe_cmp(const void *a
, const void *b
)
1966 const struct cmd_token
*first
= *(struct cmd_token
* const *)a
;
1967 const struct cmd_token
*second
= *(struct cmd_token
* const *)b
;
1969 return strcmp(first
->cmd
, second
->cmd
);
1973 cmd_describe_sort(vector matchvec
)
1975 qsort(matchvec
->index
, vector_active(matchvec
),
1976 sizeof(void*), cmd_describe_cmp
);
1979 /* '?' describe command support. */
1981 cmd_describe_command_real (vector vline
, struct vty
*vty
, int *status
)
1985 #define INIT_MATCHVEC_SIZE 10
1987 struct cmd_element
*cmd_element
;
1990 enum match_type match
;
1992 vector matches
= NULL
;
1993 vector match_vector
;
1994 uint32_t command_found
= 0;
1995 const char *last_word
;
1998 if (vector_active (vline
) == 0)
2000 *status
= CMD_ERR_NO_MATCH
;
2004 index
= vector_active (vline
) - 1;
2006 /* Make copy vector of current node's command vector. */
2007 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2009 /* Prepare match vector */
2010 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2012 /* Filter commands and build a list how they could possibly continue. */
2013 for (i
= 0; i
<= index
; i
++)
2015 command
= vector_slot (vline
, i
);
2018 cmd_matches_free(&matches
);
2020 ret
= cmd_vector_filter(cmd_vector
,
2026 if (ret
!= CMD_SUCCESS
)
2028 vector_free (cmd_vector
);
2029 vector_free (matchvec
);
2030 cmd_matches_free(&matches
);
2035 /* The last match may well be ambigious, so break here */
2039 if (match
== vararg_match
)
2041 /* We found a vararg match - so we can throw out the current matches here
2042 * and don't need to continue checking the command input */
2045 for (j
= 0; j
< vector_active (matches
); j
++)
2046 if ((match_vector
= vector_slot (matches
, j
)) != NULL
)
2047 for (k
= 0; k
< vector_active (match_vector
); k
++)
2049 struct cmd_token
*token
= vector_slot (match_vector
, k
);
2050 vector_set (matchvec
, token
);
2053 *status
= CMD_SUCCESS
;
2054 vector_set(matchvec
, &token_cr
);
2055 vector_free (cmd_vector
);
2056 cmd_matches_free(&matches
);
2057 cmd_describe_sort(matchvec
);
2061 ret
= is_cmd_ambiguous(cmd_vector
, command
, matches
, match
);
2064 vector_free (cmd_vector
);
2065 vector_free (matchvec
);
2066 cmd_matches_free(&matches
);
2067 *status
= CMD_ERR_AMBIGUOUS
;
2072 vector_free (cmd_vector
);
2073 vector_free (matchvec
);
2074 cmd_matches_free(&matches
);
2075 *status
= CMD_ERR_NO_MATCH
;
2080 /* Make description vector. */
2081 for (i
= 0; i
< vector_active (matches
); i
++) {
2082 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
&&
2083 !(cmd_element
->attr
== CMD_ATTR_DEPRECATED
||
2084 cmd_element
->attr
== CMD_ATTR_HIDDEN
))
2087 vector vline_trimmed
;
2090 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2091 if (last_word
== NULL
|| !strlen(last_word
))
2093 vline_trimmed
= vector_copy(vline
);
2094 vector_unset(vline_trimmed
, vector_active(vline_trimmed
) - 1);
2096 if (cmd_is_complete(cmd_element
, vline_trimmed
)
2097 && desc_unique_string(matchvec
, command_cr
))
2099 if (match
!= vararg_match
)
2100 vector_set(matchvec
, &token_cr
);
2103 vector_free(vline_trimmed
);
2106 match_vector
= vector_slot (matches
, i
);
2108 for (j
= 0; j
< vector_active(match_vector
); j
++)
2110 struct cmd_token
*token
= vector_slot(match_vector
, j
);
2113 string
= cmd_entry_function_desc(command
, token
);
2114 if (string
&& desc_unique_string(matchvec
, string
))
2115 vector_set(matchvec
, token
);
2121 * We can get into this situation when the command is complete
2122 * but the last part of the command is an optional piece of
2125 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2126 if (command_found
== 0 && (last_word
== NULL
|| !strlen(last_word
))) {
2127 vector_set(matchvec
, &token_cr
);
2130 vector_free (cmd_vector
);
2131 cmd_matches_free(&matches
);
2133 if (vector_slot (matchvec
, 0) == NULL
)
2135 vector_free (matchvec
);
2136 *status
= CMD_ERR_NO_MATCH
;
2140 *status
= CMD_SUCCESS
;
2141 cmd_describe_sort(matchvec
);
2146 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
2150 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2152 enum node_type onode
;
2153 vector shifted_vline
;
2157 vty
->node
= ENABLE_NODE
;
2158 /* We can try it on enable node, cos' the vty is authenticated */
2160 shifted_vline
= vector_init (vector_count(vline
));
2162 for (index
= 1; index
< vector_active (vline
); index
++)
2164 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2167 ret
= cmd_describe_command_real (shifted_vline
, vty
, status
);
2169 vector_free(shifted_vline
);
2175 return cmd_describe_command_real (vline
, vty
, status
);
2179 /* Check LCD of matched command. */
2181 cmd_lcd (char **matched
)
2189 if (matched
[0] == NULL
|| matched
[1] == NULL
)
2192 for (i
= 1; matched
[i
] != NULL
; i
++)
2194 s1
= matched
[i
- 1];
2197 for (j
= 0; (c1
= s1
[j
]) && (c2
= s2
[j
]); j
++)
2213 cmd_complete_cmp(const void *a
, const void *b
)
2215 const char *first
= *(char * const *)a
;
2216 const char *second
= *(char * const *)b
;
2227 return strcmp(first
, second
);
2231 cmd_complete_sort(vector matchvec
)
2233 qsort(matchvec
->index
, vector_active(matchvec
),
2234 sizeof(void*), cmd_complete_cmp
);
2237 /* Command line completion support. */
2239 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
, int islib
)
2242 vector cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2243 #define INIT_MATCHVEC_SIZE 10
2247 struct cmd_token
*token
;
2250 vector matches
= NULL
;
2251 vector match_vector
;
2253 if (vector_active (vline
) == 0)
2255 vector_free (cmd_vector
);
2256 *status
= CMD_ERR_NO_MATCH
;
2260 index
= vector_active (vline
) - 1;
2262 /* First, filter by command string */
2263 for (i
= 0; i
<= index
; i
++)
2265 command
= vector_slot (vline
, i
);
2266 enum match_type match
;
2270 cmd_matches_free(&matches
);
2272 /* First try completion match, if there is exactly match return 1 */
2273 ret
= cmd_vector_filter(cmd_vector
,
2279 if (ret
!= CMD_SUCCESS
)
2281 vector_free(cmd_vector
);
2282 cmd_matches_free(&matches
);
2287 /* Break here - the completion mustn't be checked to be non-ambiguous */
2291 /* If there is exact match then filter ambiguous match else check
2293 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2296 vector_free (cmd_vector
);
2297 cmd_matches_free(&matches
);
2298 *status
= CMD_ERR_AMBIGUOUS
;
2303 /* Prepare match vector. */
2304 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2306 /* Build the possible list of continuations into a list of completions */
2307 for (i
= 0; i
< vector_active (matches
); i
++)
2308 if ((match_vector
= vector_slot (matches
, i
)))
2313 for (j
= 0; j
< vector_active (match_vector
); j
++)
2314 if ((token
= vector_slot (match_vector
, j
)))
2316 string
= cmd_entry_function (vector_slot (vline
, index
),
2318 if (string
&& cmd_unique_string (matchvec
, string
))
2319 vector_set (matchvec
, (islib
!= 0 ?
2320 XSTRDUP (MTYPE_TMP
, string
) :
2321 strdup (string
) /* rl freed */));
2325 /* We don't need cmd_vector any more. */
2326 vector_free (cmd_vector
);
2327 cmd_matches_free(&matches
);
2329 /* No matched command */
2330 if (vector_slot (matchvec
, 0) == NULL
)
2332 vector_free (matchvec
);
2334 /* In case of 'command \t' pattern. Do you need '?' command at
2335 the end of the line. */
2336 if (vector_slot (vline
, index
) == '\0')
2337 *status
= CMD_ERR_NOTHING_TODO
;
2339 *status
= CMD_ERR_NO_MATCH
;
2343 /* Only one matched */
2344 if (vector_slot (matchvec
, 1) == NULL
)
2346 match_str
= (char **) matchvec
->index
;
2347 vector_only_wrapper_free (matchvec
);
2348 *status
= CMD_COMPLETE_FULL_MATCH
;
2351 /* Make it sure last element is NULL. */
2352 vector_set (matchvec
, NULL
);
2354 /* Check LCD of matched strings. */
2355 if (vector_slot (vline
, index
) != NULL
)
2357 lcd
= cmd_lcd ((char **) matchvec
->index
);
2361 int len
= strlen (vector_slot (vline
, index
));
2367 lcdstr
= (islib
!= 0 ?
2368 XMALLOC (MTYPE_TMP
, lcd
+ 1) :
2370 memcpy (lcdstr
, matchvec
->index
[0], lcd
);
2373 /* Free matchvec. */
2374 for (i
= 0; i
< vector_active (matchvec
); i
++)
2376 if (vector_slot (matchvec
, i
))
2379 XFREE (MTYPE_TMP
, vector_slot (matchvec
, i
));
2381 free (vector_slot (matchvec
, i
));
2384 vector_free (matchvec
);
2386 /* Make new matchvec. */
2387 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2388 vector_set (matchvec
, lcdstr
);
2389 match_str
= (char **) matchvec
->index
;
2390 vector_only_wrapper_free (matchvec
);
2392 *status
= CMD_COMPLETE_MATCH
;
2398 match_str
= (char **) matchvec
->index
;
2399 cmd_complete_sort(matchvec
);
2400 vector_only_wrapper_free (matchvec
);
2401 *status
= CMD_COMPLETE_LIST_MATCH
;
2406 cmd_complete_command_lib (vector vline
, struct vty
*vty
, int *status
, int islib
)
2410 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2412 enum node_type onode
;
2413 vector shifted_vline
;
2417 vty
->node
= ENABLE_NODE
;
2418 /* We can try it on enable node, cos' the vty is authenticated */
2420 shifted_vline
= vector_init (vector_count(vline
));
2422 for (index
= 1; index
< vector_active (vline
); index
++)
2424 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2427 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
, islib
);
2429 vector_free(shifted_vline
);
2434 return cmd_complete_command_real (vline
, vty
, status
, islib
);
2438 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
2440 return cmd_complete_command_lib (vline
, vty
, status
, 0);
2443 /* return parent node */
2444 /* MUST eventually converge on CONFIG_NODE */
2446 node_parent ( enum node_type node
)
2450 assert (node
> CONFIG_NODE
);
2454 case BGP_VPNV4_NODE
:
2455 case BGP_VPNV6_NODE
:
2456 case BGP_ENCAP_NODE
:
2457 case BGP_ENCAPV6_NODE
:
2459 case BGP_IPV4M_NODE
:
2461 case BGP_IPV6M_NODE
:
2464 case KEYCHAIN_KEY_NODE
:
2465 ret
= KEYCHAIN_NODE
;
2474 /* Execute command by argument vline vector. */
2476 cmd_execute_command_real (vector vline
,
2477 enum filter_type filter
,
2479 struct cmd_element
**cmd
)
2484 struct cmd_element
*cmd_element
;
2485 struct cmd_element
*matched_element
;
2486 unsigned int matched_count
, incomplete_count
;
2488 const char *argv
[CMD_ARGC_MAX
];
2489 enum match_type match
= 0;
2494 /* Make copy of command elements. */
2495 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2497 for (index
= 0; index
< vector_active (vline
); index
++)
2499 command
= vector_slot (vline
, index
);
2500 ret
= cmd_vector_filter(cmd_vector
,
2506 if (ret
!= CMD_SUCCESS
)
2508 cmd_matches_free(&matches
);
2512 if (match
== vararg_match
)
2514 cmd_matches_free(&matches
);
2518 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2519 cmd_matches_free(&matches
);
2523 vector_free(cmd_vector
);
2524 return CMD_ERR_AMBIGUOUS
;
2528 vector_free(cmd_vector
);
2529 return CMD_ERR_NO_MATCH
;
2533 /* Check matched count. */
2534 matched_element
= NULL
;
2536 incomplete_count
= 0;
2538 for (i
= 0; i
< vector_active (cmd_vector
); i
++)
2539 if ((cmd_element
= vector_slot (cmd_vector
, i
)))
2541 if (cmd_is_complete(cmd_element
, vline
))
2543 matched_element
= cmd_element
;
2552 /* Finish of using cmd_vector. */
2553 vector_free (cmd_vector
);
2555 /* To execute command, matched_count must be 1. */
2556 if (matched_count
== 0)
2558 if (incomplete_count
)
2559 return CMD_ERR_INCOMPLETE
;
2561 return CMD_ERR_NO_MATCH
;
2564 if (matched_count
> 1)
2565 return CMD_ERR_AMBIGUOUS
;
2567 ret
= cmd_parse(matched_element
, vline
, &argc
, argv
);
2568 if (ret
!= CMD_SUCCESS
)
2571 /* For vtysh execution. */
2573 *cmd
= matched_element
;
2575 if (matched_element
->daemon
)
2576 return CMD_SUCCESS_DAEMON
;
2578 /* Execute matched command. */
2579 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2583 * Execute a given command, handling things like "do ..." and checking
2584 * whether the given command might apply at a parent node if doesn't
2585 * apply for the current node.
2587 * @param vline Command line input, vector of char* where each element is
2589 * @param vty The vty context in which the command should be executed.
2590 * @param cmd Pointer where the struct cmd_element of the matched command
2591 * will be stored, if any. May be set to NULL if this info is
2593 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2594 * @return The status of the command that has been executed or an error code
2595 * as to why no command could be executed.
2598 cmd_execute_command (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
,
2600 int ret
, saved_ret
= 0;
2601 enum node_type onode
, try_node
;
2603 onode
= try_node
= vty
->node
;
2605 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2607 vector shifted_vline
;
2610 vty
->node
= ENABLE_NODE
;
2611 /* We can try it on enable node, cos' the vty is authenticated */
2613 shifted_vline
= vector_init (vector_count(vline
));
2615 for (index
= 1; index
< vector_active (vline
); index
++)
2616 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2618 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
2620 vector_free(shifted_vline
);
2626 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2631 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
)
2633 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2634 while (vty
->node
> CONFIG_NODE
)
2636 try_node
= node_parent(try_node
);
2637 vty
->node
= try_node
;
2638 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2639 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
2642 /* no command succeeded, reset the vty to the original node */
2646 /* return command status for original node */
2651 * Execute a given command, matching it strictly against the current node.
2652 * This mode is used when reading config files.
2654 * @param vline Command line input, vector of char* where each element is
2656 * @param vty The vty context in which the command should be executed.
2657 * @param cmd Pointer where the struct cmd_element* of the matched command
2658 * will be stored, if any. May be set to NULL if this info is
2660 * @return The status of the command that has been executed or an error code
2661 * as to why no command could be executed.
2664 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
2665 struct cmd_element
**cmd
)
2667 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
2671 * Parse one line of config, walking up the parse tree attempting to find a match
2673 * @param vty The vty context in which the command should be executed.
2674 * @param cmd Pointer where the struct cmd_element* of the match command
2675 * will be stored, if any. May be set to NULL if this info is
2677 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2679 * @return The status of the command that has been executed or an error code
2680 * as to why no command could be executed.
2683 command_config_read_one_line (struct vty
*vty
, struct cmd_element
**cmd
, int use_daemon
)
2689 vline
= cmd_make_strvec (vty
->buf
);
2691 /* In case of comment line */
2695 /* Execute configuration command : this is strict match */
2696 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2698 // Climb the tree and try the command again at each node
2699 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2700 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2701 ret
!= CMD_SUCCESS
&&
2702 ret
!= CMD_WARNING
&&
2703 vty
->node
!= CONFIG_NODE
) {
2705 saved_node
= vty
->node
;
2707 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2708 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2709 ret
!= CMD_SUCCESS
&&
2710 ret
!= CMD_WARNING
&&
2711 vty
->node
> CONFIG_NODE
) {
2712 vty
->node
= node_parent(vty
->node
);
2713 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2716 // If climbing the tree did not work then ignore the command and
2717 // stay at the same node
2718 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2719 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2720 ret
!= CMD_SUCCESS
&&
2723 vty
->node
= saved_node
;
2724 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
2728 cmd_free_strvec (vline
);
2733 /* Configuration make from file. */
2735 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
2737 int ret
, error_ret
=0;
2740 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
2745 ret
= command_config_read_one_line (vty
, NULL
, 0);
2747 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
2748 ret
!= CMD_ERR_NOTHING_TODO
)
2759 /* Configuration from terminal */
2760 DEFUN (config_terminal
,
2761 config_terminal_cmd
,
2762 "configure terminal",
2763 "Configuration from vty interface\n"
2764 "Configuration terminal\n")
2766 if (vty_config_lock (vty
))
2767 vty
->node
= CONFIG_NODE
;
2770 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
2776 /* Enable command */
2780 "Turn on privileged mode command\n")
2782 /* If enable password is NULL, change to ENABLE_NODE */
2783 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
2784 vty
->type
== VTY_SHELL_SERV
)
2785 vty
->node
= ENABLE_NODE
;
2787 vty
->node
= AUTH_ENABLE_NODE
;
2792 /* Disable command */
2796 "Turn off privileged mode command\n")
2798 if (vty
->node
== ENABLE_NODE
)
2799 vty
->node
= VIEW_NODE
;
2803 /* Down vty node level. */
2807 "Exit current mode and down to previous mode\n")
2813 case RESTRICTED_NODE
:
2814 if (vty_shell (vty
))
2817 vty
->status
= VTY_CLOSE
;
2820 vty
->node
= ENABLE_NODE
;
2821 vty_config_unlock (vty
);
2823 case INTERFACE_NODE
:
2837 vty
->node
= CONFIG_NODE
;
2840 case BGP_IPV4M_NODE
:
2841 case BGP_VPNV4_NODE
:
2842 case BGP_VPNV6_NODE
:
2843 case BGP_ENCAP_NODE
:
2844 case BGP_ENCAPV6_NODE
:
2846 case BGP_IPV6M_NODE
:
2847 vty
->node
= BGP_NODE
;
2849 case KEYCHAIN_KEY_NODE
:
2850 vty
->node
= KEYCHAIN_NODE
;
2858 /* quit is alias of exit. */
2862 "Exit current mode and down to previous mode\n")
2864 /* End of configuration. */
2868 "End current mode and change to enable mode.")
2874 case RESTRICTED_NODE
:
2875 /* Nothing to do. */
2878 case INTERFACE_NODE
:
2884 case BGP_ENCAP_NODE
:
2885 case BGP_ENCAPV6_NODE
:
2886 case BGP_VPNV4_NODE
:
2887 case BGP_VPNV6_NODE
:
2889 case BGP_IPV4M_NODE
:
2891 case BGP_IPV6M_NODE
:
2897 case KEYCHAIN_KEY_NODE
:
2901 vty_config_unlock (vty
);
2902 vty
->node
= ENABLE_NODE
;
2911 DEFUN (show_version
,
2915 "Displays zebra version\n")
2917 vty_out (vty
, "Quagga %s (%s).%s", QUAGGA_VERSION
, host
.name
?host
.name
:"",
2919 vty_out (vty
, "%s%s%s", QUAGGA_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
2920 vty_out (vty
, "configured with:%s %s%s", VTY_NEWLINE
,
2921 QUAGGA_CONFIG_ARGS
, VTY_NEWLINE
);
2926 /* Help display function for all node. */
2930 "Description of the interactive help system\n")
2933 "Quagga VTY provides advanced help feature. When you need help,%s\
2934 anytime at the command line please press '?'.%s\
2936 If nothing matches, the help list will be empty and you must backup%s\
2937 until entering a '?' shows the available options.%s\
2938 Two styles of help are provided:%s\
2939 1. Full help is available when you are ready to enter a%s\
2940 command argument (e.g. 'show ?') and describes each possible%s\
2942 2. Partial help is provided when an abbreviated argument is entered%s\
2943 and you want to know what arguments match the input%s\
2944 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
2945 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
2946 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
2950 /* Help display function for all node. */
2954 "Print command list\n")
2957 struct cmd_node
*cnode
= vector_slot (cmdvec
, vty
->node
);
2958 struct cmd_element
*cmd
;
2960 for (i
= 0; i
< vector_active (cnode
->cmd_vector
); i
++)
2961 if ((cmd
= vector_slot (cnode
->cmd_vector
, i
)) != NULL
2962 && !(cmd
->attr
== CMD_ATTR_DEPRECATED
2963 || cmd
->attr
== CMD_ATTR_HIDDEN
))
2964 vty_out (vty
, " %s%s", cmd
->string
,
2969 /* Write current configuration into file. */
2970 DEFUN (config_write_file
,
2971 config_write_file_cmd
,
2973 "Write running configuration to memory, network, or terminal\n"
2974 "Write to configuration file\n")
2978 struct cmd_node
*node
;
2980 char *config_file_tmp
= NULL
;
2981 char *config_file_sav
= NULL
;
2982 int ret
= CMD_WARNING
;
2983 struct vty
*file_vty
;
2984 struct stat conf_stat
;
2986 /* Check and see if we are operating under vtysh configuration */
2987 if (host
.config
== NULL
)
2989 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
2995 config_file
= host
.config
;
2998 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
2999 strcpy (config_file_sav
, config_file
);
3000 strcat (config_file_sav
, CONF_BACKUP_EXT
);
3003 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
3004 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
3006 /* Open file to configuration write. */
3007 fd
= mkstemp (config_file_tmp
);
3010 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
3015 /* Make vty for configuration file. */
3016 file_vty
= vty_new ();
3018 file_vty
->type
= VTY_FILE
;
3020 /* Config file header print. */
3021 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
3022 vty_time_print (file_vty
, 1);
3023 vty_out (file_vty
, "!\n");
3025 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3026 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3028 if ((*node
->func
) (file_vty
))
3029 vty_out (file_vty
, "!\n");
3031 vty_close (file_vty
);
3033 if (stat(config_file
, &conf_stat
) >= 0)
3035 if (unlink (config_file_sav
) != 0)
3036 if (errno
!= ENOENT
)
3038 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
3042 if (link (config_file
, config_file_sav
) != 0)
3044 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
3049 if (unlink (config_file
) != 0)
3051 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
3056 if (link (config_file_tmp
, config_file
) != 0)
3058 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
3064 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
3066 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
3067 config_file
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
3071 vty_out (vty
, "Configuration saved to %s%s", config_file
,
3076 unlink (config_file_tmp
);
3077 XFREE (MTYPE_TMP
, config_file_tmp
);
3078 XFREE (MTYPE_TMP
, config_file_sav
);
3082 ALIAS (config_write_file
,
3085 "Write running configuration to memory, network, or terminal\n")
3087 ALIAS (config_write_file
,
3088 config_write_memory_cmd
,
3090 "Write running configuration to memory, network, or terminal\n"
3091 "Write configuration to the file (same as write file)\n")
3093 ALIAS (config_write_file
,
3094 copy_runningconfig_startupconfig_cmd
,
3095 "copy running-config startup-config",
3096 "Copy configuration\n"
3097 "Copy running config to... \n"
3098 "Copy running config to startup config (same as write file)\n")
3100 /* Write current configuration into the terminal. */
3101 DEFUN (config_write_terminal
,
3102 config_write_terminal_cmd
,
3104 "Write running configuration to memory, network, or terminal\n"
3105 "Write to terminal\n")
3108 struct cmd_node
*node
;
3110 if (vty
->type
== VTY_SHELL_SERV
)
3112 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3113 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
3115 if ((*node
->func
) (vty
))
3116 vty_out (vty
, "!%s", VTY_NEWLINE
);
3121 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
3123 vty_out (vty
, "!%s", VTY_NEWLINE
);
3125 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3126 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3128 if ((*node
->func
) (vty
))
3129 vty_out (vty
, "!%s", VTY_NEWLINE
);
3131 vty_out (vty
, "end%s",VTY_NEWLINE
);
3136 /* Write current configuration into the terminal. */
3137 ALIAS (config_write_terminal
,
3138 show_running_config_cmd
,
3139 "show running-config",
3141 "running configuration\n")
3143 /* Write startup configuration into the terminal. */
3144 DEFUN (show_startup_config
,
3145 show_startup_config_cmd
,
3146 "show startup-config",
3148 "Contentes of startup configuration\n")
3153 confp
= fopen (host
.config
, "r");
3156 vty_out (vty
, "Can't open configuration file [%s] due to '%s'%s",
3157 host
.config
, safe_strerror(errno
), VTY_NEWLINE
);
3161 while (fgets (buf
, BUFSIZ
, confp
))
3165 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
3169 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
3177 /* Hostname configuration */
3178 DEFUN (config_hostname
,
3181 "Set system's network name\n"
3182 "This system's network name\n")
3184 if (!isalpha((int) *argv
[0]))
3186 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
3191 XFREE (MTYPE_HOST
, host
.name
);
3193 host
.name
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3197 DEFUN (config_no_hostname
,
3199 "no hostname [HOSTNAME]",
3201 "Reset system's network name\n"
3202 "Host name of this router\n")
3205 XFREE (MTYPE_HOST
, host
.name
);
3210 /* VTY interface password set. */
3211 DEFUN (config_password
, password_cmd
,
3212 "password (8|) WORD",
3213 "Assign the terminal connection password\n"
3214 "Specifies a HIDDEN password will follow\n"
3216 "The HIDDEN line password string\n")
3218 /* Argument check. */
3221 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3227 if (*argv
[0] == '8')
3230 XFREE (MTYPE_HOST
, host
.password
);
3231 host
.password
= NULL
;
3232 if (host
.password_encrypt
)
3233 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3234 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3239 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3244 if (!isalnum ((int) *argv
[0]))
3247 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3252 XFREE (MTYPE_HOST
, host
.password
);
3253 host
.password
= NULL
;
3257 if (host
.password_encrypt
)
3258 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3259 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3262 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3267 ALIAS (config_password
, password_text_cmd
,
3269 "Assign the terminal connection password\n"
3270 "The UNENCRYPTED (cleartext) line password\n")
3272 /* VTY enable password set. */
3273 DEFUN (config_enable_password
, enable_password_cmd
,
3274 "enable password (8|) WORD",
3275 "Modify enable password parameters\n"
3276 "Assign the privileged level password\n"
3277 "Specifies a HIDDEN password will follow\n"
3279 "The HIDDEN 'enable' password string\n")
3281 /* Argument check. */
3284 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3288 /* Crypt type is specified. */
3291 if (*argv
[0] == '8')
3294 XFREE (MTYPE_HOST
, host
.enable
);
3297 if (host
.enable_encrypt
)
3298 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3299 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3305 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3310 if (!isalnum ((int) *argv
[0]))
3313 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3318 XFREE (MTYPE_HOST
, host
.enable
);
3321 /* Plain password input. */
3324 if (host
.enable_encrypt
)
3325 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3326 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3329 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3334 ALIAS (config_enable_password
,
3335 enable_password_text_cmd
,
3336 "enable password LINE",
3337 "Modify enable password parameters\n"
3338 "Assign the privileged level password\n"
3339 "The UNENCRYPTED (cleartext) 'enable' password\n")
3341 /* VTY enable password delete. */
3342 DEFUN (no_config_enable_password
, no_enable_password_cmd
,
3343 "no enable password",
3345 "Modify enable password parameters\n"
3346 "Assign the privileged level password\n")
3349 XFREE (MTYPE_HOST
, host
.enable
);
3352 if (host
.enable_encrypt
)
3353 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3354 host
.enable_encrypt
= NULL
;
3359 DEFUN (service_password_encrypt
,
3360 service_password_encrypt_cmd
,
3361 "service password-encryption",
3362 "Set up miscellaneous service\n"
3363 "Enable encrypted passwords\n")
3372 if (host
.password_encrypt
)
3373 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3374 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
3378 if (host
.enable_encrypt
)
3379 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3380 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
3386 DEFUN (no_service_password_encrypt
,
3387 no_service_password_encrypt_cmd
,
3388 "no service password-encryption",
3390 "Set up miscellaneous service\n"
3391 "Enable encrypted passwords\n")
3398 if (host
.password_encrypt
)
3399 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3400 host
.password_encrypt
= NULL
;
3402 if (host
.enable_encrypt
)
3403 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3404 host
.enable_encrypt
= NULL
;
3409 DEFUN (config_terminal_length
, config_terminal_length_cmd
,
3410 "terminal length <0-512>",
3411 "Set terminal line parameters\n"
3412 "Set number of lines on a screen\n"
3413 "Number of lines on screen (0 for no pausing)\n")
3416 char *endptr
= NULL
;
3418 lines
= strtol (argv
[0], &endptr
, 10);
3419 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3421 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3429 DEFUN (config_terminal_no_length
, config_terminal_no_length_cmd
,
3430 "terminal no length",
3431 "Set terminal line parameters\n"
3433 "Set number of lines on a screen\n")
3439 DEFUN (service_terminal_length
, service_terminal_length_cmd
,
3440 "service terminal-length <0-512>",
3441 "Set up miscellaneous service\n"
3442 "System wide terminal length configuration\n"
3443 "Number of lines of VTY (0 means no line control)\n")
3446 char *endptr
= NULL
;
3448 lines
= strtol (argv
[0], &endptr
, 10);
3449 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3451 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3459 DEFUN (no_service_terminal_length
, no_service_terminal_length_cmd
,
3460 "no service terminal-length [<0-512>]",
3462 "Set up miscellaneous service\n"
3463 "System wide terminal length configuration\n"
3464 "Number of lines of VTY (0 means no line control)\n")
3470 DEFUN_HIDDEN (do_echo
,
3473 "Echo a message back to the vty\n"
3474 "The message to echo\n")
3478 vty_out (vty
, "%s%s", ((message
= argv_concat(argv
, argc
, 0)) ? message
: ""),
3481 XFREE(MTYPE_TMP
, message
);
3485 DEFUN (config_logmsg
,
3487 "logmsg "LOG_LEVELS
" .MESSAGE",
3488 "Send a message to enabled logging destinations\n"
3490 "The message to send\n")
3495 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3496 return CMD_ERR_NO_MATCH
;
3498 zlog(NULL
, level
, "%s", ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
3500 XFREE(MTYPE_TMP
, message
);
3504 DEFUN (show_logging
,
3508 "Show current logging configuration\n")
3510 struct zlog
*zl
= zlog_default
;
3512 vty_out (vty
, "Syslog logging: ");
3513 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
3514 vty_out (vty
, "disabled");
3516 vty_out (vty
, "level %s, facility %s, ident %s",
3517 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
3518 facility_name(zl
->facility
), zl
->ident
);
3519 vty_out (vty
, "%s", VTY_NEWLINE
);
3521 vty_out (vty
, "Stdout logging: ");
3522 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
3523 vty_out (vty
, "disabled");
3525 vty_out (vty
, "level %s",
3526 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
3527 vty_out (vty
, "%s", VTY_NEWLINE
);
3529 vty_out (vty
, "Monitor logging: ");
3530 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
3531 vty_out (vty
, "disabled");
3533 vty_out (vty
, "level %s",
3534 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
3535 vty_out (vty
, "%s", VTY_NEWLINE
);
3537 vty_out (vty
, "File logging: ");
3538 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
3540 vty_out (vty
, "disabled");
3542 vty_out (vty
, "level %s, filename %s",
3543 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
3545 vty_out (vty
, "%s", VTY_NEWLINE
);
3547 vty_out (vty
, "Protocol name: %s%s",
3548 zlog_proto_names
[zl
->protocol
], VTY_NEWLINE
);
3549 vty_out (vty
, "Record priority: %s%s",
3550 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
3551 vty_out (vty
, "Timestamp precision: %d%s",
3552 zl
->timestamp_precision
, VTY_NEWLINE
);
3557 DEFUN (config_log_stdout
,
3558 config_log_stdout_cmd
,
3561 "Set stdout logging level\n")
3563 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
3567 DEFUN (config_log_stdout_level
,
3568 config_log_stdout_level_cmd
,
3569 "log stdout "LOG_LEVELS
,
3571 "Set stdout logging level\n"
3576 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3577 return CMD_ERR_NO_MATCH
;
3578 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, level
);
3582 DEFUN (no_config_log_stdout
,
3583 no_config_log_stdout_cmd
,
3584 "no log stdout [LEVEL]",
3587 "Cancel logging to stdout\n"
3590 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
3594 DEFUN (config_log_monitor
,
3595 config_log_monitor_cmd
,
3598 "Set terminal line (monitor) logging level\n")
3600 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
3604 DEFUN (config_log_monitor_level
,
3605 config_log_monitor_level_cmd
,
3606 "log monitor "LOG_LEVELS
,
3608 "Set terminal line (monitor) logging level\n"
3613 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3614 return CMD_ERR_NO_MATCH
;
3615 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, level
);
3619 DEFUN (no_config_log_monitor
,
3620 no_config_log_monitor_cmd
,
3621 "no log monitor [LEVEL]",
3624 "Disable terminal line (monitor) logging\n"
3627 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
3632 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
3636 const char *fullpath
;
3638 /* Path detection. */
3639 if (! IS_DIRECTORY_SEP (*fname
))
3641 char cwd
[MAXPATHLEN
+1];
3642 cwd
[MAXPATHLEN
] = '\0';
3644 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
3646 zlog_err ("config_log_file: Unable to alloc mem!");
3650 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
3653 zlog_err ("config_log_file: Unable to alloc mem!");
3656 sprintf (p
, "%s/%s", cwd
, fname
);
3662 ret
= zlog_set_file (NULL
, fullpath
, loglevel
);
3665 XFREE (MTYPE_TMP
, p
);
3669 vty_out (vty
, "can't open logfile %s\n", fname
);
3674 XFREE (MTYPE_HOST
, host
.logfile
);
3676 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
3681 DEFUN (config_log_file
,
3682 config_log_file_cmd
,
3683 "log file FILENAME",
3686 "Logging filename\n")
3688 return set_log_file(vty
, argv
[0], zlog_default
->default_lvl
);
3691 DEFUN (config_log_file_level
,
3692 config_log_file_level_cmd
,
3693 "log file FILENAME "LOG_LEVELS
,
3696 "Logging filename\n"
3701 if ((level
= level_match(argv
[1])) == ZLOG_DISABLED
)
3702 return CMD_ERR_NO_MATCH
;
3703 return set_log_file(vty
, argv
[0], level
);
3706 DEFUN (no_config_log_file
,
3707 no_config_log_file_cmd
,
3708 "no log file [FILENAME]",
3711 "Cancel logging to file\n"
3712 "Logging file name\n")
3714 zlog_reset_file (NULL
);
3717 XFREE (MTYPE_HOST
, host
.logfile
);
3719 host
.logfile
= NULL
;
3724 ALIAS (no_config_log_file
,
3725 no_config_log_file_level_cmd
,
3726 "no log file FILENAME LEVEL",
3729 "Cancel logging to file\n"
3730 "Logging file name\n"
3733 DEFUN (config_log_syslog
,
3734 config_log_syslog_cmd
,
3737 "Set syslog logging level\n")
3739 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3743 DEFUN (config_log_syslog_level
,
3744 config_log_syslog_level_cmd
,
3745 "log syslog "LOG_LEVELS
,
3747 "Set syslog logging level\n"
3752 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3753 return CMD_ERR_NO_MATCH
;
3754 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, level
);
3758 DEFUN_DEPRECATED (config_log_syslog_facility
,
3759 config_log_syslog_facility_cmd
,
3760 "log syslog facility "LOG_FACILITIES
,
3762 "Logging goes to syslog\n"
3763 "(Deprecated) Facility parameter for syslog messages\n"
3768 if ((facility
= facility_match(argv
[0])) < 0)
3769 return CMD_ERR_NO_MATCH
;
3771 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3772 zlog_default
->facility
= facility
;
3776 DEFUN (no_config_log_syslog
,
3777 no_config_log_syslog_cmd
,
3778 "no log syslog [LEVEL]",
3781 "Cancel logging to syslog\n"
3784 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
3788 ALIAS (no_config_log_syslog
,
3789 no_config_log_syslog_facility_cmd
,
3790 "no log syslog facility "LOG_FACILITIES
,
3793 "Logging goes to syslog\n"
3794 "Facility parameter for syslog messages\n"
3797 DEFUN (config_log_facility
,
3798 config_log_facility_cmd
,
3799 "log facility "LOG_FACILITIES
,
3801 "Facility parameter for syslog messages\n"
3806 if ((facility
= facility_match(argv
[0])) < 0)
3807 return CMD_ERR_NO_MATCH
;
3808 zlog_default
->facility
= facility
;
3812 DEFUN (no_config_log_facility
,
3813 no_config_log_facility_cmd
,
3814 "no log facility [FACILITY]",
3817 "Reset syslog facility to default (daemon)\n"
3818 "Syslog facility\n")
3820 zlog_default
->facility
= LOG_DAEMON
;
3824 DEFUN_DEPRECATED (config_log_trap
,
3825 config_log_trap_cmd
,
3826 "log trap "LOG_LEVELS
,
3828 "(Deprecated) Set logging level and default for all destinations\n"
3834 if ((new_level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3835 return CMD_ERR_NO_MATCH
;
3837 zlog_default
->default_lvl
= new_level
;
3838 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
3839 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
3840 zlog_default
->maxlvl
[i
] = new_level
;
3844 DEFUN_DEPRECATED (no_config_log_trap
,
3845 no_config_log_trap_cmd
,
3846 "no log trap [LEVEL]",
3849 "Permit all logging information\n"
3852 zlog_default
->default_lvl
= LOG_DEBUG
;
3856 DEFUN (config_log_record_priority
,
3857 config_log_record_priority_cmd
,
3858 "log record-priority",
3860 "Log the priority of the message within the message\n")
3862 zlog_default
->record_priority
= 1 ;
3866 DEFUN (no_config_log_record_priority
,
3867 no_config_log_record_priority_cmd
,
3868 "no log record-priority",
3871 "Do not log the priority of the message within the message\n")
3873 zlog_default
->record_priority
= 0 ;
3877 DEFUN (config_log_timestamp_precision
,
3878 config_log_timestamp_precision_cmd
,
3879 "log timestamp precision <0-6>",
3881 "Timestamp configuration\n"
3882 "Set the timestamp precision\n"
3883 "Number of subsecond digits\n")
3887 vty_out (vty
, "Insufficient arguments%s", VTY_NEWLINE
);
3891 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3892 zlog_default
->timestamp_precision
, argv
[0], 0, 6);
3896 DEFUN (no_config_log_timestamp_precision
,
3897 no_config_log_timestamp_precision_cmd
,
3898 "no log timestamp precision",
3901 "Timestamp configuration\n"
3902 "Reset the timestamp precision to the default value of 0\n")
3904 zlog_default
->timestamp_precision
= 0 ;
3909 cmd_banner_motd_file (const char *file
)
3912 XFREE (MTYPE_HOST
, host
.motdfile
);
3913 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
3918 DEFUN (banner_motd_file
,
3919 banner_motd_file_cmd
,
3920 "banner motd file FILE",
3923 "Banner from a file\n"
3926 return cmd_banner_motd_file (argv
[0]);
3929 DEFUN (banner_motd_default
,
3930 banner_motd_default_cmd
,
3931 "banner motd default",
3932 "Set banner string\n"
3933 "Strings for motd\n"
3936 host
.motd
= default_motd
;
3940 DEFUN (no_banner_motd
,
3944 "Set banner string\n"
3945 "Strings for motd\n")
3949 XFREE (MTYPE_HOST
, host
.motdfile
);
3950 host
.motdfile
= NULL
;
3954 DEFUN (show_commandtree
,
3955 show_commandtree_cmd
,
3958 "Show command tree\n")
3964 vty_out (vty
, "Current node id: %d%s", vty
->node
, VTY_NEWLINE
);
3966 /* vector of all commands installed at this node */
3967 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
3969 /* loop over all commands at this node */
3970 for (i
= 0; i
< vector_active(cmd_vector
); ++i
)
3972 struct cmd_element
*cmd_element
;
3974 /* A cmd_element (seems to be) is an individual command */
3975 if ((cmd_element
= vector_slot (cmd_vector
, i
)) == NULL
)
3978 vty_out (vty
, " %s%s", cmd_element
->string
, VTY_NEWLINE
);
3981 vector_free (cmd_vector
);
3985 /* Set config filename. Called from vty.c */
3987 host_config_set (const char *filename
)
3990 XFREE (MTYPE_HOST
, host
.config
);
3991 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
3995 install_default (enum node_type node
)
3997 install_element (node
, &config_exit_cmd
);
3998 install_element (node
, &config_quit_cmd
);
3999 install_element (node
, &config_end_cmd
);
4000 install_element (node
, &config_help_cmd
);
4001 install_element (node
, &config_list_cmd
);
4003 install_element (node
, &config_write_terminal_cmd
);
4004 install_element (node
, &config_write_file_cmd
);
4005 install_element (node
, &config_write_memory_cmd
);
4006 install_element (node
, &config_write_cmd
);
4007 install_element (node
, &show_running_config_cmd
);
4010 /* Initialize command interface. Install basic nodes and commands. */
4012 cmd_init (int terminal
)
4014 command_cr
= XSTRDUP(MTYPE_CMD_TOKENS
, "<cr>");
4015 token_cr
.type
= TOKEN_TERMINAL
;
4016 token_cr
.terminal
= TERMINAL_LITERAL
;
4017 token_cr
.cmd
= command_cr
;
4018 token_cr
.desc
= XSTRDUP(MTYPE_CMD_TOKENS
, "");
4020 /* Allocate initial top vector of commands. */
4021 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
4023 /* Default host value settings. */
4025 host
.password
= NULL
;
4027 host
.logfile
= NULL
;
4030 host
.motd
= default_motd
;
4031 host
.motdfile
= NULL
;
4033 /* Install top nodes. */
4034 install_node (&view_node
, NULL
);
4035 install_node (&enable_node
, NULL
);
4036 install_node (&auth_node
, NULL
);
4037 install_node (&auth_enable_node
, NULL
);
4038 install_node (&restricted_node
, NULL
);
4039 install_node (&config_node
, config_write_host
);
4041 /* Each node's basic commands. */
4042 install_element (VIEW_NODE
, &show_version_cmd
);
4045 install_element (VIEW_NODE
, &config_list_cmd
);
4046 install_element (VIEW_NODE
, &config_exit_cmd
);
4047 install_element (VIEW_NODE
, &config_quit_cmd
);
4048 install_element (VIEW_NODE
, &config_help_cmd
);
4049 install_element (VIEW_NODE
, &config_enable_cmd
);
4050 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
4051 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
4052 install_element (VIEW_NODE
, &show_logging_cmd
);
4053 install_element (VIEW_NODE
, &show_commandtree_cmd
);
4054 install_element (VIEW_NODE
, &echo_cmd
);
4056 install_element (RESTRICTED_NODE
, &config_list_cmd
);
4057 install_element (RESTRICTED_NODE
, &config_exit_cmd
);
4058 install_element (RESTRICTED_NODE
, &config_quit_cmd
);
4059 install_element (RESTRICTED_NODE
, &config_help_cmd
);
4060 install_element (RESTRICTED_NODE
, &config_enable_cmd
);
4061 install_element (RESTRICTED_NODE
, &config_terminal_length_cmd
);
4062 install_element (RESTRICTED_NODE
, &config_terminal_no_length_cmd
);
4063 install_element (RESTRICTED_NODE
, &show_commandtree_cmd
);
4064 install_element (RESTRICTED_NODE
, &echo_cmd
);
4069 install_default (ENABLE_NODE
);
4070 install_element (ENABLE_NODE
, &config_disable_cmd
);
4071 install_element (ENABLE_NODE
, &config_terminal_cmd
);
4072 install_element (ENABLE_NODE
, ©_runningconfig_startupconfig_cmd
);
4074 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
4075 install_element (ENABLE_NODE
, &show_version_cmd
);
4076 install_element (ENABLE_NODE
, &show_commandtree_cmd
);
4080 install_element (ENABLE_NODE
, &config_terminal_length_cmd
);
4081 install_element (ENABLE_NODE
, &config_terminal_no_length_cmd
);
4082 install_element (ENABLE_NODE
, &show_logging_cmd
);
4083 install_element (ENABLE_NODE
, &echo_cmd
);
4084 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
4086 install_default (CONFIG_NODE
);
4089 install_element (CONFIG_NODE
, &hostname_cmd
);
4090 install_element (CONFIG_NODE
, &no_hostname_cmd
);
4094 install_element (CONFIG_NODE
, &password_cmd
);
4095 install_element (CONFIG_NODE
, &password_text_cmd
);
4096 install_element (CONFIG_NODE
, &enable_password_cmd
);
4097 install_element (CONFIG_NODE
, &enable_password_text_cmd
);
4098 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
4100 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
4101 install_element (CONFIG_NODE
, &config_log_stdout_level_cmd
);
4102 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
4103 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
4104 install_element (CONFIG_NODE
, &config_log_monitor_level_cmd
);
4105 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
4106 install_element (CONFIG_NODE
, &config_log_file_cmd
);
4107 install_element (CONFIG_NODE
, &config_log_file_level_cmd
);
4108 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
4109 install_element (CONFIG_NODE
, &no_config_log_file_level_cmd
);
4110 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
4111 install_element (CONFIG_NODE
, &config_log_syslog_level_cmd
);
4112 install_element (CONFIG_NODE
, &config_log_syslog_facility_cmd
);
4113 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
4114 install_element (CONFIG_NODE
, &no_config_log_syslog_facility_cmd
);
4115 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
4116 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
4117 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
4118 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
4119 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
4120 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
4121 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
4122 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
4123 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
4124 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
4125 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
4126 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
4127 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
4128 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
4129 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
4131 install_element (VIEW_NODE
, &show_thread_cpu_cmd
);
4132 install_element (ENABLE_NODE
, &show_thread_cpu_cmd
);
4133 install_element (RESTRICTED_NODE
, &show_thread_cpu_cmd
);
4135 install_element (ENABLE_NODE
, &clear_thread_cpu_cmd
);
4136 install_element (VIEW_NODE
, &show_work_queues_cmd
);
4137 install_element (ENABLE_NODE
, &show_work_queues_cmd
);
4139 vrf_install_commands ();
4141 install_element (CONFIG_NODE
, &show_commandtree_cmd
);
4142 srandom(time(NULL
));
4146 cmd_terminate_token(struct cmd_token
*token
)
4149 vector keyword_vect
;
4151 if (token
->multiple
)
4153 for (i
= 0; i
< vector_active(token
->multiple
); i
++)
4154 cmd_terminate_token(vector_slot(token
->multiple
, i
));
4155 vector_free(token
->multiple
);
4156 token
->multiple
= NULL
;
4161 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
4163 keyword_vect
= vector_slot(token
->keyword
, i
);
4164 for (j
= 0; j
< vector_active(keyword_vect
); j
++)
4165 cmd_terminate_token(vector_slot(keyword_vect
, j
));
4166 vector_free(keyword_vect
);
4168 vector_free(token
->keyword
);
4169 token
->keyword
= NULL
;
4172 XFREE(MTYPE_CMD_TOKENS
, token
->cmd
);
4173 XFREE(MTYPE_CMD_TOKENS
, token
->desc
);
4175 XFREE(MTYPE_CMD_TOKENS
, token
);
4179 cmd_terminate_element(struct cmd_element
*cmd
)
4183 if (cmd
->tokens
== NULL
)
4186 for (i
= 0; i
< vector_active(cmd
->tokens
); i
++)
4187 cmd_terminate_token(vector_slot(cmd
->tokens
, i
));
4189 vector_free(cmd
->tokens
);
4194 free_cmd_element(struct cmd_element
*cmd
)
4197 free ((char*) cmd
->string
);
4198 free ((char*) cmd
->doc
);
4199 cmd_terminate_element(cmd
);
4203 struct cmd_element
*
4204 copy_cmd_element(struct cmd_element
*cmd
)
4206 struct cmd_element
*el
= XMALLOC(MTYPE_CMD_TOKENS
, sizeof (struct cmd_element
));
4207 el
->string
= cmd
->string
? XSTRDUP(MTYPE_CMD_TOKENS
, cmd
->string
) : NULL
;
4208 el
->func
= cmd
->func
;
4209 el
->doc
= cmd
->doc
? XSTRDUP(MTYPE_CMD_TOKENS
, cmd
->doc
) : NULL
;
4210 el
->daemon
= cmd
->daemon
;
4211 el
->tokens
= cmd
->tokens
? vector_copy(cmd
->tokens
) : NULL
;
4212 el
->attr
= cmd
->attr
;
4213 fprintf(stderr
, "successful copy\n");
4221 struct cmd_node
*cmd_node
;
4222 struct cmd_element
*cmd_element
;
4227 for (i
= 0; i
< vector_active (cmdvec
); i
++)
4228 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
4230 cmd_node_v
= cmd_node
->cmd_vector
;
4232 for (j
= 0; j
< vector_active (cmd_node_v
); j
++)
4233 if ((cmd_element
= vector_slot (cmd_node_v
, j
)) != NULL
)
4234 cmd_terminate_element(cmd_element
);
4236 vector_free (cmd_node_v
);
4239 vector_free (cmdvec
);
4244 XFREE(MTYPE_CMD_TOKENS
, command_cr
);
4246 XFREE(MTYPE_CMD_TOKENS
, token_cr
.desc
);
4248 XFREE (MTYPE_HOST
, host
.name
);
4250 XFREE (MTYPE_HOST
, host
.password
);
4251 if (host
.password_encrypt
)
4252 XFREE (MTYPE_HOST
, host
.password_encrypt
);
4254 XFREE (MTYPE_HOST
, host
.enable
);
4255 if (host
.enable_encrypt
)
4256 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
4258 XFREE (MTYPE_HOST
, host
.logfile
);
4260 XFREE (MTYPE_HOST
, host
.motdfile
);
4262 XFREE (MTYPE_HOST
, host
.config
);