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 DEFINE_MTYPE( LIB
, HOST
, "Host config")
38 DEFINE_MTYPE( LIB
, STRVEC
, "String vector")
39 DEFINE_MTYPE_STATIC(LIB
, CMD_TOKENS
, "Command desc")
41 /* Command vector which includes some level of command lists. Normally
42 each daemon maintains each own cmdvec. */
45 struct cmd_token token_cr
;
46 char *command_cr
= NULL
;
49 * Filter types. These tell the parser whether to allow
50 * partial matching on tokens.
59 * Command matcher result value.
68 MATCHER_EXCEED_ARGC_MAX
72 * Defines which matcher_rv values constitute
73 * an error. Should be used against matcher_rv
74 * return values to do basic error checking.
76 #define MATCHER_ERROR(matcher_rv) \
77 ( (matcher_rv) == MATCHER_INCOMPLETE \
78 || (matcher_rv) == MATCHER_NO_MATCH \
79 || (matcher_rv) == MATCHER_AMBIGUOUS \
80 || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
83 /* Host information structure. */
86 /* Standard command node structures. */
87 static struct cmd_node auth_node
=
93 static struct cmd_node view_node
=
99 static struct cmd_node restricted_node
=
105 static struct cmd_node auth_enable_node
=
111 static struct cmd_node enable_node
=
117 static struct cmd_node config_node
=
124 /* Default motd string. */
125 static const char *default_motd
=
127 Hello, this is " QUAGGA_PROGNAME
" (version " QUAGGA_VERSION
").\r\n\
128 " QUAGGA_COPYRIGHT
"\r\n\
132 static const struct facility_map
{
136 } syslog_facilities
[] =
138 { LOG_KERN
, "kern", 1 },
139 { LOG_USER
, "user", 2 },
140 { LOG_MAIL
, "mail", 1 },
141 { LOG_DAEMON
, "daemon", 1 },
142 { LOG_AUTH
, "auth", 1 },
143 { LOG_SYSLOG
, "syslog", 1 },
144 { LOG_LPR
, "lpr", 2 },
145 { LOG_NEWS
, "news", 1 },
146 { LOG_UUCP
, "uucp", 2 },
147 { LOG_CRON
, "cron", 1 },
149 { LOG_FTP
, "ftp", 1 },
151 { LOG_LOCAL0
, "local0", 6 },
152 { LOG_LOCAL1
, "local1", 6 },
153 { LOG_LOCAL2
, "local2", 6 },
154 { LOG_LOCAL3
, "local3", 6 },
155 { LOG_LOCAL4
, "local4", 6 },
156 { LOG_LOCAL5
, "local5", 6 },
157 { LOG_LOCAL6
, "local6", 6 },
158 { LOG_LOCAL7
, "local7", 6 },
163 facility_name(int facility
)
165 const struct facility_map
*fm
;
167 for (fm
= syslog_facilities
; fm
->name
; fm
++)
168 if (fm
->facility
== facility
)
174 facility_match(const char *str
)
176 const struct facility_map
*fm
;
178 for (fm
= syslog_facilities
; fm
->name
; fm
++)
179 if (!strncmp(str
,fm
->name
,fm
->match
))
185 level_match(const char *s
)
189 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
190 if (!strncmp (s
, zlog_priority
[level
], 2))
192 return ZLOG_DISABLED
;
195 /* This is called from main when a daemon is invoked with -v or --version. */
197 print_version (const char *progname
)
199 printf ("%s version %s\n", progname
, QUAGGA_VERSION
);
200 printf ("%s\n", QUAGGA_COPYRIGHT
);
201 printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS
);
205 /* Utility function to concatenate argv argument into a single string
206 with inserting ' ' character between each argument. */
208 argv_concat (const char **argv
, int argc
, int shift
)
216 for (i
= shift
; i
< argc
; i
++)
217 len
+= strlen(argv
[i
])+1;
220 p
= str
= XMALLOC(MTYPE_TMP
, len
);
221 for (i
= shift
; i
< argc
; i
++)
224 memcpy(p
, argv
[i
], (arglen
= strlen(argv
[i
])));
232 /* Install top node of command vector. */
234 install_node (struct cmd_node
*node
,
235 int (*func
) (struct vty
*))
237 vector_set_index (cmdvec
, node
->node
, node
);
239 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
242 /* Breaking up string into each command piece. I assume given
243 character is separated by a space character. Return value is a
244 vector which includes char ** data element. */
246 cmd_make_strvec (const char *string
)
248 const char *cp
, *start
;
258 /* Skip white spaces. */
259 while (isspace ((int) *cp
) && *cp
!= '\0')
262 /* Return if there is only white spaces */
266 if (*cp
== '!' || *cp
== '#')
269 /* Prepare return vector. */
270 strvec
= vector_init (VECTOR_MIN_SIZE
);
272 /* Copy each command piece and set into vector. */
276 while (!(isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n') &&
280 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
281 memcpy (token
, start
, strlen
);
282 *(token
+ strlen
) = '\0';
283 vector_set (strvec
, token
);
285 while ((isspace ((int) *cp
) || *cp
== '\n' || *cp
== '\r') &&
294 /* Free allocated string vector. */
296 cmd_free_strvec (vector v
)
304 for (i
= 0; i
< vector_active (v
); i
++)
305 if ((cp
= vector_slot (v
, i
)) != NULL
)
306 XFREE (MTYPE_STRVEC
, cp
);
312 * State structure for command format parser. Tracks
313 * parse tree position and miscellaneous state variables.
314 * Used when building a command vector from format strings.
316 struct format_parser_state
318 vector topvect
; /* Top level vector */
319 vector intvect
; /* Intermediate level vector, used when there's
320 a multiple in a keyword. */
321 vector curvect
; /* current vector where read tokens should be
324 const char *string
; /* pointer to command string, not modified */
325 const char *cp
; /* pointer in command string, moved along while
327 const char *dp
; /* pointer in description string, moved along while
330 int in_keyword
; /* flag to remember if we are in a keyword group */
331 int in_multiple
; /* flag to remember if we are in a multiple group */
332 int just_read_word
; /* flag to remember if the last thing we read was a
333 real word and not some abstract token */
337 format_parser_error(struct format_parser_state
*state
, const char *message
)
339 int offset
= state
->cp
- state
->string
+ 1;
341 fprintf(stderr
, "\nError parsing command: \"%s\"\n", state
->string
);
342 fprintf(stderr
, " %*c\n", offset
, '^');
343 fprintf(stderr
, "%s at offset %d.\n", message
, offset
);
344 fprintf(stderr
, "This is a programming error. Check your DEFUNs etc.\n");
349 * Reads out one section of a help string from state->dp.
350 * Leading whitespace is trimmed and the string is read until
351 * a newline is reached.
353 * @param[out] state format parser state
354 * @return the help string token read
357 format_parser_desc_str(struct format_parser_state
*state
)
359 const char *cp
, *start
;
368 /* Skip white spaces. */
369 while (isspace ((int) *cp
) && *cp
!= '\0')
372 /* Return if there is only white spaces */
378 while (!(*cp
== '\r' || *cp
== '\n') && *cp
!= '\0')
382 token
= XMALLOC (MTYPE_CMD_TOKENS
, strlen
+ 1);
383 memcpy (token
, start
, strlen
);
384 *(token
+ strlen
) = '\0';
392 * Transitions format parser state into keyword parsing mode.
393 * A cmd_token struct, `token`, representing this keyword token is initialized
394 * and appended to state->curvect. token->keyword is initialized as a vector of
395 * vector, a new vector is initialized and added to token->keyword, and
396 * state->curvect is set to point at this vector. When control returns to the
397 * caller newly parsed tokens will be added to this vector.
400 * state->curvect[HEAD] = new cmd_token
401 * state->curvect[HEAD]->keyword[0] = new vector
402 * state->curvect = state->curvect[HEAD]->keyword[0]
404 * @param[out] state state struct to transition
407 format_parser_begin_keyword(struct format_parser_state
*state
)
409 struct cmd_token
*token
;
412 if (state
->in_keyword
413 || state
->in_multiple
)
414 format_parser_error(state
, "Unexpected '{'");
417 state
->in_keyword
= 1;
419 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
420 token
->type
= TOKEN_KEYWORD
;
421 token
->keyword
= vector_init(VECTOR_MIN_SIZE
);
423 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
424 vector_set(token
->keyword
, keyword_vect
);
426 vector_set(state
->curvect
, token
);
427 state
->curvect
= keyword_vect
;
431 * Transitions format parser state into multiple parsing mode.
432 * A cmd_token struct, `token`, representing this multiple token is initialized
433 * and appended to state->curvect. token->multiple is initialized as a vector
434 * of cmd_token and state->curvect is set to point at token->multiple. If
435 * state->curvect != state->topvect (i.e. this multiple token is nested inside
436 * another composite token) then a pointer to state->curvect is saved in
440 * state->curvect[HEAD] = new cmd_token
441 * state->curvect[HEAD]->multiple = new vector
442 * state->intvect = state->curvect IFF nested token
443 * state->curvect = state->curvect[HEAD]->multiple
445 * @param[out] state state struct to transition
448 format_parser_begin_multiple(struct format_parser_state
*state
)
450 struct cmd_token
*token
;
452 if (state
->in_keyword
== 1)
453 format_parser_error(state
, "Keyword starting with '('");
455 if (state
->in_multiple
)
456 format_parser_error(state
, "Nested group");
459 state
->in_multiple
= 1;
460 state
->just_read_word
= 0;
462 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
463 token
->type
= TOKEN_MULTIPLE
;
464 token
->multiple
= vector_init(VECTOR_MIN_SIZE
);
466 vector_set(state
->curvect
, token
);
467 if (state
->curvect
!= state
->topvect
)
468 state
->intvect
= state
->curvect
;
469 state
->curvect
= token
->multiple
;
473 * Transition format parser state out of keyword parsing mode.
474 * This function is called upon encountering '}'.
475 * state->curvect is reassigned to the top level vector (as
476 * keywords cannot be nested) and state flags are set appropriately.
478 * @param[out] state state struct to transition
481 format_parser_end_keyword(struct format_parser_state
*state
)
483 if (state
->in_multiple
484 || !state
->in_keyword
)
485 format_parser_error(state
, "Unexpected '}'");
487 if (state
->in_keyword
== 1)
488 format_parser_error(state
, "Empty keyword group");
491 state
->in_keyword
= 0;
492 state
->curvect
= state
->topvect
;
496 * Transition format parser state out of multiple parsing mode.
497 * This function is called upon encountering ')'.
498 * state->curvect is reassigned to its parent vector (state->intvect
499 * if the multiple token being exited was nested inside another token,
500 * state->topvect otherwise) and state flags are set appropriately.
502 * @param[out] state state struct to transition
505 format_parser_end_multiple(struct format_parser_state
*state
)
509 if (!state
->in_multiple
)
510 format_parser_error(state
, "Unexpected ')'");
512 if (vector_active(state
->curvect
) == 0)
513 format_parser_error(state
, "Empty multiple section");
515 if (!state
->just_read_word
)
517 /* There are constructions like
518 * 'show ip ospf database ... (self-originate|)'
520 * The old parser reads a description string for the
521 * word '' between |) which will never match.
522 * Simulate this behvaior by dropping the next desc
523 * string in such a case. */
525 dummy
= format_parser_desc_str(state
);
526 XFREE(MTYPE_CMD_TOKENS
, dummy
);
530 state
->in_multiple
= 0;
533 state
->curvect
= state
->intvect
;
535 state
->curvect
= state
->topvect
;
539 * Format parser handler for pipe '|' character.
540 * This character separates subtokens in multiple and keyword type tokens.
541 * If the current token is a multiple keyword, the position pointer is
542 * simply moved past the pipe and state flags are set appropriately.
543 * If the current token is a keyword token, the position pointer is moved
544 * past the pipe. Then the cmd_token struct for the keyword is fetched and
545 * a new vector of cmd_token is appended to its vector of vector. Finally
546 * state->curvect is set to point at this new vector.
549 * state->curvect = state->topvect[HEAD]->keyword[HEAD] = new vector
551 * @param[out] state state struct to transition
554 format_parser_handle_pipe(struct format_parser_state
*state
)
556 struct cmd_token
*keyword_token
;
559 if (state
->in_multiple
)
561 state
->just_read_word
= 0;
564 else if (state
->in_keyword
)
566 state
->in_keyword
= 1;
569 keyword_token
= vector_slot(state
->topvect
,
570 vector_active(state
->topvect
) - 1);
571 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
572 vector_set(keyword_token
->keyword
, keyword_vect
);
573 state
->curvect
= keyword_vect
;
577 format_parser_error(state
, "Unexpected '|'");
582 * Format parser handler for terminal tokens.
583 * Parses the token, appends it to state->curvect, and sets
584 * state flags appropriately.
586 * @param[out] state state struct for current format parser state
589 format_parser_read_word(struct format_parser_state
*state
)
594 struct cmd_token
*token
;
598 while (state
->cp
[0] != '\0'
599 && !strchr("\r\n(){}|", state
->cp
[0])
600 && !isspace((int)state
->cp
[0]))
603 len
= state
->cp
- start
;
604 cmd
= XMALLOC(MTYPE_CMD_TOKENS
, len
+ 1);
605 memcpy(cmd
, start
, len
);
608 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
609 token
->type
= TOKEN_TERMINAL
;
610 if (strcmp (cmd
, "A.B.C.D") == 0)
611 token
->terminal
= TERMINAL_IPV4
;
612 else if (strcmp (cmd
, "A.B.C.D/M") == 0)
613 token
->terminal
= TERMINAL_IPV4_PREFIX
;
614 else if (strcmp (cmd
, "X:X::X:X") == 0)
615 token
->terminal
= TERMINAL_IPV6
;
616 else if (strcmp (cmd
, "X:X::X:X/M") == 0)
617 token
->terminal
= TERMINAL_IPV6_PREFIX
;
618 else if (cmd
[0] == '[')
619 token
->terminal
= TERMINAL_OPTION
;
620 else if (cmd
[0] == '.')
621 token
->terminal
= TERMINAL_VARARG
;
622 else if (cmd
[0] == '<')
623 token
->terminal
= TERMINAL_RANGE
;
624 else if (cmd
[0] >= 'A' && cmd
[0] <= 'Z')
625 token
->terminal
= TERMINAL_VARIABLE
;
627 token
->terminal
= TERMINAL_LITERAL
;
630 token
->desc
= format_parser_desc_str(state
);
631 vector_set(state
->curvect
, token
);
633 if (state
->in_keyword
== 1)
634 state
->in_keyword
= 2;
636 state
->just_read_word
= 1;
640 * Parse a given command format string and build a tree of tokens from
641 * it that is suitable to be used by the command subsystem.
643 * @param string Command format string.
644 * @param descstr Description string.
645 * @return A vector of struct cmd_token representing the given command,
649 cmd_parse_format(const char *string
, const char *descstr
)
651 struct format_parser_state state
;
656 memset(&state
, 0, sizeof(state
));
657 state
.topvect
= state
.curvect
= vector_init(VECTOR_MIN_SIZE
);
658 state
.cp
= state
.string
= string
;
663 while (isspace((int)state
.cp
[0]) && state
.cp
[0] != '\0')
670 || state
.in_multiple
)
671 format_parser_error(&state
, "Unclosed group/keyword");
672 return state
.topvect
;
674 format_parser_begin_keyword(&state
);
677 format_parser_begin_multiple(&state
);
680 format_parser_end_keyword(&state
);
683 format_parser_end_multiple(&state
);
686 format_parser_handle_pipe(&state
);
689 format_parser_read_word(&state
);
694 /* Return prompt character of specified node. */
696 cmd_prompt (enum node_type node
)
698 struct cmd_node
*cnode
;
700 cnode
= vector_slot (cmdvec
, node
);
701 return cnode
->prompt
;
704 /* Install a command into a node. */
706 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
708 struct cmd_node
*cnode
;
710 /* cmd_init hasn't been called */
714 cnode
= vector_slot (cmdvec
, ntype
);
718 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
723 vector_set (cnode
->cmd_vector
, cmd
);
724 if (cmd
->tokens
== NULL
)
725 cmd
->tokens
= cmd_parse_format(cmd
->string
, cmd
->doc
);
728 static const unsigned char itoa64
[] =
729 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
732 to64(char *s
, long v
, int n
)
736 *s
++ = itoa64
[v
&0x3f];
742 zencrypt (const char *passwd
)
746 char *crypt (const char *, const char *);
750 to64(&salt
[0], random(), 3);
751 to64(&salt
[3], tv
.tv_usec
, 3);
754 return crypt (passwd
, salt
);
757 /* This function write configuration of this host. */
759 config_write_host (struct vty
*vty
)
762 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
766 if (host
.password_encrypt
)
767 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
768 if (host
.enable_encrypt
)
769 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
774 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
776 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
779 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
781 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
783 vty_out (vty
, "log trap %s%s",
784 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
787 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
789 vty_out (vty
, "log file %s", host
.logfile
);
790 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
792 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
793 vty_out (vty
, "%s", VTY_NEWLINE
);
796 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
798 vty_out (vty
, "log stdout");
799 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
801 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
802 vty_out (vty
, "%s", VTY_NEWLINE
);
805 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
806 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
807 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
808 vty_out(vty
,"log monitor %s%s",
809 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
811 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
813 vty_out (vty
, "log syslog");
814 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
816 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
817 vty_out (vty
, "%s", VTY_NEWLINE
);
820 if (zlog_default
->facility
!= LOG_DAEMON
)
821 vty_out (vty
, "log facility %s%s",
822 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
824 if (zlog_default
->record_priority
== 1)
825 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
827 if (zlog_default
->timestamp_precision
> 0)
828 vty_out (vty
, "log timestamp precision %d%s",
829 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
832 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
835 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
838 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
842 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
843 else if (! host
.motd
)
844 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
849 /* Utility function for getting command vector. */
851 cmd_node_vector (vector v
, enum node_type ntype
)
853 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
854 return cnode
->cmd_vector
;
857 /* Completion match types. */
872 static enum match_type
873 cmd_ipv4_match (const char *str
)
876 int dots
= 0, nums
= 0;
884 memset (buf
, 0, sizeof (buf
));
893 if (*(str
+ 1) == '.')
896 if (*(str
+ 1) == '\0')
902 if (!isdigit ((int) *str
))
911 strncpy (buf
, sp
, str
- sp
);
912 if (atoi (buf
) > 255)
929 static enum match_type
930 cmd_ipv4_prefix_match (const char *str
)
941 memset (buf
, 0, sizeof (buf
));
943 while (*str
!= '\0' && *str
!= '/')
950 if (*(str
+ 1) == '.' || *(str
+ 1) == '/')
953 if (*(str
+ 1) == '\0')
960 if (!isdigit ((int) *str
))
969 strncpy (buf
, sp
, str
- sp
);
970 if (atoi (buf
) > 255)
977 if (*(str
+ 1) == '\0')
983 else if (*str
== '\0')
996 if (!isdigit ((int) *str
))
1008 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:."
1009 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
1013 static enum match_type
1014 cmd_ipv6_match (const char *str
)
1016 struct sockaddr_in6 sin6_dummy
;
1020 return partly_match
;
1022 if (strspn (str
, IPV6_ADDR_STR
) != strlen (str
))
1025 /* use inet_pton that has a better support,
1026 * for example inet_pton can support the automatic addresses:
1029 ret
= inet_pton(AF_INET6
, str
, &sin6_dummy
.sin6_addr
);
1037 static enum match_type
1038 cmd_ipv6_prefix_match (const char *str
)
1040 struct sockaddr_in6 sin6_dummy
;
1041 const char *delim
= "/\0";
1042 char *dupe
, *prefix
, *mask
, *context
, *endptr
;
1046 return partly_match
;
1048 if (strspn (str
, IPV6_PREFIX_STR
) != strlen (str
))
1051 /* tokenize to address + mask */
1052 dupe
= XMALLOC(MTYPE_TMP
, strlen(str
)+1);
1053 strncpy(dupe
, str
, strlen(str
)+1);
1054 prefix
= strtok_r(dupe
, delim
, &context
);
1055 mask
= strtok_r(NULL
, delim
, &context
);
1058 return partly_match
;
1060 /* validate prefix */
1061 if (inet_pton(AF_INET6
, prefix
, &sin6_dummy
.sin6_addr
) != 1)
1065 nmask
= strtol (mask
, &endptr
, 10);
1066 if (*endptr
!= '\0' || nmask
< 0 || nmask
> 128)
1069 XFREE(MTYPE_TMP
, dupe
);
1074 #endif /* HAVE_IPV6 */
1076 #define DECIMAL_STRLEN_MAX 20
1079 cmd_range_match (const char *range
, const char *str
)
1082 char buf
[DECIMAL_STRLEN_MAX
+ 1];
1083 char *endptr
= NULL
;
1084 signed long long min
, max
, val
;
1089 val
= strtoll (str
, &endptr
, 10);
1090 if (*endptr
!= '\0')
1095 p
= strchr (range
, '-');
1098 if (p
- range
> DECIMAL_STRLEN_MAX
)
1100 strncpy (buf
, range
, p
- range
);
1101 buf
[p
- range
] = '\0';
1102 min
= strtoll (buf
, &endptr
, 10);
1103 if (*endptr
!= '\0')
1107 p
= strchr (range
, '>');
1110 if (p
- range
> DECIMAL_STRLEN_MAX
)
1112 strncpy (buf
, range
, p
- range
);
1113 buf
[p
- range
] = '\0';
1114 max
= strtoll (buf
, &endptr
, 10);
1115 if (*endptr
!= '\0')
1118 if (val
< min
|| val
> max
)
1124 static enum match_type
1125 cmd_word_match(struct cmd_token
*token
,
1126 enum filter_type filter
,
1130 enum match_type match_type
;
1134 if (filter
== FILTER_RELAXED
)
1135 if (!word
|| !strlen(word
))
1136 return partly_match
;
1141 switch (token
->terminal
)
1143 case TERMINAL_VARARG
:
1144 return vararg_match
;
1146 case TERMINAL_RANGE
:
1147 if (cmd_range_match(str
, word
))
1152 match_type
= cmd_ipv6_match(word
);
1153 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1154 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1158 case TERMINAL_IPV6_PREFIX
:
1159 match_type
= cmd_ipv6_prefix_match(word
);
1160 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1161 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1162 return ipv6_prefix_match
;
1166 match_type
= cmd_ipv4_match(word
);
1167 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1168 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1172 case TERMINAL_IPV4_PREFIX
:
1173 match_type
= cmd_ipv4_prefix_match(word
);
1174 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1175 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1176 return ipv4_prefix_match
;
1179 case TERMINAL_OPTION
:
1180 case TERMINAL_VARIABLE
:
1181 return extend_match
;
1183 case TERMINAL_LITERAL
:
1184 if (filter
== FILTER_RELAXED
&& !strncmp(str
, word
, strlen(word
)))
1186 if (!strcmp(str
, word
))
1188 return partly_match
;
1190 if (filter
== FILTER_STRICT
&& !strcmp(str
, word
))
1203 struct cmd_element
*cmd
; /* The command element the matcher is using */
1204 enum filter_type filter
; /* Whether to use strict or relaxed matching */
1205 vector vline
; /* The tokenized commandline which is to be matched */
1206 unsigned int index
; /* The index up to which matching should be done */
1208 /* If set, construct a list of matches at the position given by index */
1209 enum match_type
*match_type
;
1212 unsigned int word_index
; /* iterating over vline */
1216 push_argument(int *argc
, const char **argv
, const char *arg
)
1218 if (!arg
|| !strlen(arg
))
1224 if (*argc
>= CMD_ARGC_MAX
)
1227 argv
[(*argc
)++] = arg
;
1232 cmd_matcher_record_match(struct cmd_matcher
*matcher
,
1233 enum match_type match_type
,
1234 struct cmd_token
*token
)
1236 if (matcher
->word_index
!= matcher
->index
)
1241 if (!*matcher
->match
)
1242 *matcher
->match
= vector_init(VECTOR_MIN_SIZE
);
1243 vector_set(*matcher
->match
, token
);
1246 if (matcher
->match_type
)
1248 if (match_type
> *matcher
->match_type
)
1249 *matcher
->match_type
= match_type
;
1254 cmd_matcher_words_left(struct cmd_matcher
*matcher
)
1256 return matcher
->word_index
< vector_active(matcher
->vline
);
1260 cmd_matcher_get_word(struct cmd_matcher
*matcher
)
1262 assert(cmd_matcher_words_left(matcher
));
1264 return vector_slot(matcher
->vline
, matcher
->word_index
);
1267 static enum matcher_rv
1268 cmd_matcher_match_terminal(struct cmd_matcher
*matcher
,
1269 struct cmd_token
*token
,
1270 int *argc
, const char **argv
)
1273 enum match_type word_match
;
1275 assert(token
->type
== TOKEN_TERMINAL
);
1277 if (!cmd_matcher_words_left(matcher
))
1279 if (token
->terminal
== TERMINAL_OPTION
)
1280 return MATCHER_OK
; /* missing optional args are NOT pushed as NULL */
1282 return MATCHER_INCOMPLETE
;
1285 word
= cmd_matcher_get_word(matcher
);
1286 word_match
= cmd_word_match(token
, matcher
->filter
, word
);
1287 if (word_match
== no_match
)
1288 return MATCHER_NO_MATCH
;
1290 /* We have to record the input word as argument if it matched
1291 * against a variable. */
1292 if (TERMINAL_RECORD (token
->terminal
))
1294 if (push_argument(argc
, argv
, word
))
1295 return MATCHER_EXCEED_ARGC_MAX
;
1298 cmd_matcher_record_match(matcher
, word_match
, token
);
1300 matcher
->word_index
++;
1302 /* A vararg token should consume all left over words as arguments */
1303 if (token
->terminal
== TERMINAL_VARARG
)
1304 while (cmd_matcher_words_left(matcher
))
1306 word
= cmd_matcher_get_word(matcher
);
1307 if (word
&& strlen(word
))
1308 push_argument(argc
, argv
, word
);
1309 matcher
->word_index
++;
1315 static enum matcher_rv
1316 cmd_matcher_match_multiple(struct cmd_matcher
*matcher
,
1317 struct cmd_token
*token
,
1318 int *argc
, const char **argv
)
1320 enum match_type multiple_match
;
1321 unsigned int multiple_index
;
1323 const char *arg
= NULL
;
1324 struct cmd_token
*word_token
;
1325 enum match_type word_match
;
1327 assert(token
->type
== TOKEN_MULTIPLE
);
1329 multiple_match
= no_match
;
1331 if (!cmd_matcher_words_left(matcher
))
1332 return MATCHER_INCOMPLETE
;
1334 word
= cmd_matcher_get_word(matcher
);
1335 for (multiple_index
= 0;
1336 multiple_index
< vector_active(token
->multiple
);
1339 word_token
= vector_slot(token
->multiple
, multiple_index
);
1341 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1342 if (word_match
== no_match
)
1345 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1347 if (word_match
> multiple_match
)
1349 multiple_match
= word_match
;
1352 /* To mimic the behavior of the old command implementation, we
1353 * tolerate any ambiguities here :/ */
1356 matcher
->word_index
++;
1358 if (multiple_match
== no_match
)
1359 return MATCHER_NO_MATCH
;
1361 if (push_argument(argc
, argv
, arg
))
1362 return MATCHER_EXCEED_ARGC_MAX
;
1367 static enum matcher_rv
1368 cmd_matcher_read_keywords(struct cmd_matcher
*matcher
,
1369 struct cmd_token
*token
,
1373 unsigned long keyword_mask
;
1374 unsigned int keyword_found
;
1375 enum match_type keyword_match
;
1376 enum match_type word_match
;
1377 vector keyword_vector
;
1378 struct cmd_token
*word_token
;
1381 const char **keyword_argv
;
1382 enum matcher_rv rv
= MATCHER_OK
;
1387 if (!cmd_matcher_words_left(matcher
))
1390 word
= cmd_matcher_get_word(matcher
);
1393 keyword_match
= no_match
;
1394 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1396 if (keyword_mask
& (1 << i
))
1399 keyword_vector
= vector_slot(token
->keyword
, i
);
1400 word_token
= vector_slot(keyword_vector
, 0);
1402 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1403 if (word_match
== no_match
)
1406 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1408 if (word_match
> keyword_match
)
1410 keyword_match
= word_match
;
1413 else if (word_match
== keyword_match
)
1415 if (matcher
->word_index
!= matcher
->index
|| args_vector
)
1416 return MATCHER_AMBIGUOUS
;
1420 if (keyword_found
== (unsigned int)-1)
1421 return MATCHER_NO_MATCH
;
1423 matcher
->word_index
++;
1425 if (matcher
->word_index
> matcher
->index
)
1428 keyword_mask
|= (1 << keyword_found
);
1433 keyword_argv
= XMALLOC(MTYPE_TMP
, (CMD_ARGC_MAX
+ 1) * sizeof(char*));
1434 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1435 for (i
= 0; i
< CMD_ARGC_MAX
+ 1; i
++)
1436 keyword_argv
[i
] = (void*)-1;
1437 vector_set_index(args_vector
, keyword_found
, keyword_argv
);
1441 keyword_argv
= NULL
;
1444 keyword_vector
= vector_slot(token
->keyword
, keyword_found
);
1445 /* the keyword itself is at 0. We are only interested in the arguments,
1446 * so start counting at 1. */
1447 for (i
= 1; i
< vector_active(keyword_vector
); i
++)
1449 word_token
= vector_slot(keyword_vector
, i
);
1451 switch (word_token
->type
)
1453 case TOKEN_TERMINAL
:
1454 rv
= cmd_matcher_match_terminal(matcher
, word_token
,
1455 &keyword_argc
, keyword_argv
);
1457 case TOKEN_MULTIPLE
:
1458 rv
= cmd_matcher_match_multiple(matcher
, word_token
,
1459 &keyword_argc
, keyword_argv
);
1462 assert(!"Keywords should never be nested.");
1466 if (MATCHER_ERROR(rv
))
1469 if (matcher
->word_index
> matcher
->index
)
1476 static enum matcher_rv
1477 cmd_matcher_build_keyword_args(struct cmd_matcher
*matcher
,
1478 struct cmd_token
*token
,
1479 int *argc
, const char **argv
,
1480 vector keyword_args_vector
)
1483 const char **keyword_args
;
1484 vector keyword_vector
;
1485 struct cmd_token
*word_token
;
1491 if (keyword_args_vector
== NULL
)
1494 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1496 keyword_vector
= vector_slot(token
->keyword
, i
);
1497 keyword_args
= vector_lookup(keyword_args_vector
, i
);
1499 if (vector_active(keyword_vector
) == 1)
1501 /* this is a keyword without arguments */
1504 word_token
= vector_slot(keyword_vector
, 0);
1505 arg
= word_token
->cmd
;
1506 XFREE (MTYPE_TMP
, keyword_args
);
1513 if (push_argument(argc
, argv
, arg
))
1514 rv
= MATCHER_EXCEED_ARGC_MAX
;
1518 /* this is a keyword with arguments */
1521 /* the keyword was present, so just fill in the arguments */
1522 for (j
= 0; keyword_args
[j
] != (void*)-1; j
++)
1523 if (push_argument(argc
, argv
, keyword_args
[j
]))
1524 rv
= MATCHER_EXCEED_ARGC_MAX
;
1525 XFREE(MTYPE_TMP
, keyword_args
);
1529 /* the keyword was not present, insert NULL for the arguments
1530 * the keyword would have taken. */
1531 for (j
= 1; j
< vector_active(keyword_vector
); j
++)
1533 word_token
= vector_slot(keyword_vector
, j
);
1534 if ((word_token
->type
== TOKEN_TERMINAL
1535 && TERMINAL_RECORD (word_token
->terminal
))
1536 || word_token
->type
== TOKEN_MULTIPLE
)
1538 if (push_argument(argc
, argv
, NULL
))
1539 rv
= MATCHER_EXCEED_ARGC_MAX
;
1545 vector_free(keyword_args_vector
);
1549 static enum matcher_rv
1550 cmd_matcher_match_keyword(struct cmd_matcher
*matcher
,
1551 struct cmd_token
*token
,
1552 int *argc
, const char **argv
)
1554 vector keyword_args_vector
;
1555 enum matcher_rv reader_rv
;
1556 enum matcher_rv builder_rv
;
1558 assert(token
->type
== TOKEN_KEYWORD
);
1561 keyword_args_vector
= vector_init(VECTOR_MIN_SIZE
);
1563 keyword_args_vector
= NULL
;
1565 reader_rv
= cmd_matcher_read_keywords(matcher
, token
, keyword_args_vector
);
1566 builder_rv
= cmd_matcher_build_keyword_args(matcher
, token
, argc
,
1567 argv
, keyword_args_vector
);
1568 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1570 if (!MATCHER_ERROR(reader_rv
) && MATCHER_ERROR(builder_rv
))
1577 cmd_matcher_init(struct cmd_matcher
*matcher
,
1578 struct cmd_element
*cmd
,
1579 enum filter_type filter
,
1582 enum match_type
*match_type
,
1585 memset(matcher
, 0, sizeof(*matcher
));
1588 matcher
->filter
= filter
;
1589 matcher
->vline
= vline
;
1590 matcher
->index
= index
;
1592 matcher
->match_type
= match_type
;
1593 if (matcher
->match_type
)
1594 *matcher
->match_type
= no_match
;
1595 matcher
->match
= match
;
1597 matcher
->word_index
= 0;
1600 static enum matcher_rv
1601 cmd_element_match(struct cmd_element
*cmd_element
,
1602 enum filter_type filter
,
1605 enum match_type
*match_type
,
1610 struct cmd_matcher matcher
;
1611 unsigned int token_index
;
1612 enum matcher_rv rv
= MATCHER_OK
;
1614 cmd_matcher_init(&matcher
, cmd_element
, filter
,
1615 vline
, index
, match_type
, match
);
1620 for (token_index
= 0;
1621 token_index
< vector_active(cmd_element
->tokens
);
1624 struct cmd_token
*token
= vector_slot(cmd_element
->tokens
, token_index
);
1626 switch (token
->type
)
1628 case TOKEN_TERMINAL
:
1629 rv
= cmd_matcher_match_terminal(&matcher
, token
, argc
, argv
);
1631 case TOKEN_MULTIPLE
:
1632 rv
= cmd_matcher_match_multiple(&matcher
, token
, argc
, argv
);
1635 rv
= cmd_matcher_match_keyword(&matcher
, token
, argc
, argv
);
1638 if (MATCHER_ERROR(rv
))
1641 if (matcher
.word_index
> index
)
1645 /* return MATCHER_COMPLETE if all words were consumed */
1646 if (matcher
.word_index
>= vector_active(vline
))
1647 return MATCHER_COMPLETE
;
1649 /* return MATCHER_COMPLETE also if only an empty word is left. */
1650 if (matcher
.word_index
== vector_active(vline
) - 1
1651 && (!vector_slot(vline
, matcher
.word_index
)
1652 || !strlen((char*)vector_slot(vline
, matcher
.word_index
))))
1653 return MATCHER_COMPLETE
;
1655 return MATCHER_NO_MATCH
; /* command is too long to match */
1659 * Filter a given vector of commands against a given commandline and
1660 * calculate possible completions.
1662 * @param commands A vector of struct cmd_element*. Commands that don't
1663 * match against the given command line will be overwritten
1664 * with NULL in that vector.
1665 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1666 * determines how incomplete commands are handled, compare with
1667 * cmd_word_match for details.
1668 * @param vline A vector of char* containing the tokenized commandline.
1669 * @param index Only match up to the given token of the commandline.
1670 * @param match_type Record the type of the best match here.
1671 * @param matches Record the matches here. For each cmd_element in the commands
1672 * vector, a match vector will be created in the matches vector.
1673 * That vector will contain all struct command_token* of the
1674 * cmd_element which matched against the given vline at the given
1676 * @return A code specifying if an error occured. If all went right, it's
1680 cmd_vector_filter(vector commands
,
1681 enum filter_type filter
,
1684 enum match_type
*match_type
,
1688 struct cmd_element
*cmd_element
;
1689 enum match_type best_match
;
1690 enum match_type element_match
;
1691 enum matcher_rv matcher_rv
;
1693 best_match
= no_match
;
1694 *matches
= vector_init(VECTOR_MIN_SIZE
);
1696 for (i
= 0; i
< vector_active (commands
); i
++)
1697 if ((cmd_element
= vector_slot (commands
, i
)) != NULL
)
1699 vector_set_index(*matches
, i
, NULL
);
1700 matcher_rv
= cmd_element_match(cmd_element
, filter
,
1703 (vector
*)&vector_slot(*matches
, i
),
1705 if (MATCHER_ERROR(matcher_rv
))
1707 vector_slot(commands
, i
) = NULL
;
1708 if (matcher_rv
== MATCHER_AMBIGUOUS
)
1709 return CMD_ERR_AMBIGUOUS
;
1710 if (matcher_rv
== MATCHER_EXCEED_ARGC_MAX
)
1711 return CMD_ERR_EXEED_ARGC_MAX
;
1713 else if (element_match
> best_match
)
1715 best_match
= element_match
;
1718 *match_type
= best_match
;
1723 * Check whether a given commandline is complete if used for a specific
1726 * @param cmd_element A cmd_element against which the commandline should be
1728 * @param vline The tokenized commandline.
1729 * @return 1 if the given commandline is complete, 0 otherwise.
1732 cmd_is_complete(struct cmd_element
*cmd_element
,
1737 rv
= cmd_element_match(cmd_element
,
1742 return (rv
== MATCHER_COMPLETE
);
1746 * Parse a given commandline and construct a list of arguments for the
1747 * given command_element.
1749 * @param cmd_element The cmd_element for which we want to construct arguments.
1750 * @param vline The tokenized commandline.
1751 * @param argc Where to store the argument count.
1752 * @param argv Where to store the argument list. Should be at least
1753 * CMD_ARGC_MAX elements long.
1754 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1757 cmd_parse(struct cmd_element
*cmd_element
,
1759 int *argc
, const char **argv
)
1761 enum matcher_rv rv
= cmd_element_match(cmd_element
,
1768 case MATCHER_COMPLETE
:
1771 case MATCHER_NO_MATCH
:
1772 return CMD_ERR_NO_MATCH
;
1774 case MATCHER_AMBIGUOUS
:
1775 return CMD_ERR_AMBIGUOUS
;
1777 case MATCHER_EXCEED_ARGC_MAX
:
1778 return CMD_ERR_EXEED_ARGC_MAX
;
1781 return CMD_ERR_INCOMPLETE
;
1785 /* Check ambiguous match */
1787 is_cmd_ambiguous (vector cmd_vector
,
1788 const char *command
,
1790 enum match_type type
)
1794 const char *str
= NULL
;
1795 const char *matched
= NULL
;
1796 vector match_vector
;
1797 struct cmd_token
*cmd_token
;
1799 if (command
== NULL
)
1802 for (i
= 0; i
< vector_active (matches
); i
++)
1803 if ((match_vector
= vector_slot (matches
, i
)) != NULL
)
1807 for (j
= 0; j
< vector_active (match_vector
); j
++)
1808 if ((cmd_token
= vector_slot (match_vector
, j
)) != NULL
)
1810 enum match_type ret
;
1812 assert(cmd_token
->type
== TOKEN_TERMINAL
);
1813 if (cmd_token
->type
!= TOKEN_TERMINAL
)
1816 str
= cmd_token
->cmd
;
1821 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1822 && strcmp (command
, str
) == 0)
1826 if (!TERMINAL_RECORD (cmd_token
->terminal
)
1827 && strncmp (command
, str
, strlen (command
)) == 0)
1829 if (matched
&& strcmp (matched
, str
) != 0)
1830 return 1; /* There is ambiguous match. */
1837 if (cmd_range_match (str
, command
))
1839 if (matched
&& strcmp (matched
, str
) != 0)
1848 if (cmd_token
->terminal
== TERMINAL_IPV6
)
1851 case ipv6_prefix_match
:
1852 if ((ret
= cmd_ipv6_prefix_match (command
)) != no_match
)
1854 if (ret
== partly_match
)
1855 return 2; /* There is incomplete match. */
1860 #endif /* HAVE_IPV6 */
1862 if (cmd_token
->terminal
== TERMINAL_IPV4
)
1865 case ipv4_prefix_match
:
1866 if ((ret
= cmd_ipv4_prefix_match (command
)) != no_match
)
1868 if (ret
== partly_match
)
1869 return 2; /* There is incomplete match. */
1875 if (TERMINAL_RECORD (cmd_token
->terminal
))
1884 vector_slot (cmd_vector
, i
) = NULL
;
1889 /* If src matches dst return dst string, otherwise return NULL */
1891 cmd_entry_function (const char *src
, struct cmd_token
*token
)
1893 const char *dst
= token
->cmd
;
1895 /* Skip variable arguments. */
1896 if (TERMINAL_RECORD (token
->terminal
))
1899 /* In case of 'command \t', given src is NULL string. */
1903 /* Matched with input string. */
1904 if (strncmp (src
, dst
, strlen (src
)) == 0)
1910 /* If src matches dst return dst string, otherwise return NULL */
1911 /* This version will return the dst string always if it is
1912 CMD_VARIABLE for '?' key processing */
1914 cmd_entry_function_desc (const char *src
, struct cmd_token
*token
)
1916 const char *dst
= token
->cmd
;
1918 switch (token
->terminal
)
1920 case TERMINAL_VARARG
:
1923 case TERMINAL_RANGE
:
1924 if (cmd_range_match (dst
, src
))
1930 if (cmd_ipv6_match (src
))
1935 case TERMINAL_IPV6_PREFIX
:
1936 if (cmd_ipv6_prefix_match (src
))
1942 if (cmd_ipv4_match (src
))
1947 case TERMINAL_IPV4_PREFIX
:
1948 if (cmd_ipv4_prefix_match (src
))
1953 /* Optional or variable commands always match on '?' */
1954 case TERMINAL_OPTION
:
1955 case TERMINAL_VARIABLE
:
1958 case TERMINAL_LITERAL
:
1959 /* In case of 'command \t', given src is NULL string. */
1963 if (strncmp (src
, dst
, strlen (src
)) == 0)
1975 * Check whether a string is already present in a vector of strings.
1976 * @param v A vector of char*.
1977 * @param str A char*.
1978 * @return 0 if str is already present in the vector, 1 otherwise.
1981 cmd_unique_string (vector v
, const char *str
)
1986 for (i
= 0; i
< vector_active (v
); i
++)
1987 if ((match
= vector_slot (v
, i
)) != NULL
)
1988 if (strcmp (match
, str
) == 0)
1994 * Check whether a struct cmd_token matching a given string is already
1995 * present in a vector of struct cmd_token.
1996 * @param v A vector of struct cmd_token*.
1997 * @param str A char* which should be searched for.
1998 * @return 0 if there is a struct cmd_token* with its cmd matching str,
2002 desc_unique_string (vector v
, const char *str
)
2005 struct cmd_token
*token
;
2007 for (i
= 0; i
< vector_active (v
); i
++)
2008 if ((token
= vector_slot (v
, i
)) != NULL
)
2009 if (strcmp (token
->cmd
, str
) == 0)
2015 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
2016 if ( first_word
!= NULL
&&
2017 node
!= AUTH_NODE
&&
2018 node
!= VIEW_NODE
&&
2019 node
!= AUTH_ENABLE_NODE
&&
2020 node
!= ENABLE_NODE
&&
2021 node
!= RESTRICTED_NODE
&&
2022 0 == strcmp( "do", first_word
) )
2028 cmd_matches_free(vector
*matches
)
2033 for (i
= 0; i
< vector_active(*matches
); i
++)
2034 if ((cmd_matches
= vector_slot(*matches
, i
)) != NULL
)
2035 vector_free(cmd_matches
);
2036 vector_free(*matches
);
2041 cmd_describe_cmp(const void *a
, const void *b
)
2043 const struct cmd_token
*first
= *(struct cmd_token
* const *)a
;
2044 const struct cmd_token
*second
= *(struct cmd_token
* const *)b
;
2046 return strcmp(first
->cmd
, second
->cmd
);
2050 cmd_describe_sort(vector matchvec
)
2052 qsort(matchvec
->index
, vector_active(matchvec
),
2053 sizeof(void*), cmd_describe_cmp
);
2056 /* '?' describe command support. */
2058 cmd_describe_command_real (vector vline
, struct vty
*vty
, int *status
)
2062 #define INIT_MATCHVEC_SIZE 10
2064 struct cmd_element
*cmd_element
;
2067 enum match_type match
;
2069 vector matches
= NULL
;
2070 vector match_vector
;
2071 uint32_t command_found
= 0;
2072 const char *last_word
;
2075 if (vector_active (vline
) == 0)
2077 *status
= CMD_ERR_NO_MATCH
;
2081 index
= vector_active (vline
) - 1;
2083 /* Make copy vector of current node's command vector. */
2084 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2086 /* Prepare match vector */
2087 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2089 /* Filter commands and build a list how they could possibly continue. */
2090 for (i
= 0; i
<= index
; i
++)
2092 command
= vector_slot (vline
, i
);
2095 cmd_matches_free(&matches
);
2097 ret
= cmd_vector_filter(cmd_vector
,
2103 if (ret
!= CMD_SUCCESS
)
2105 vector_free (cmd_vector
);
2106 vector_free (matchvec
);
2107 cmd_matches_free(&matches
);
2112 /* The last match may well be ambigious, so break here */
2116 if (match
== vararg_match
)
2118 /* We found a vararg match - so we can throw out the current matches here
2119 * and don't need to continue checking the command input */
2122 for (j
= 0; j
< vector_active (matches
); j
++)
2123 if ((match_vector
= vector_slot (matches
, j
)) != NULL
)
2124 for (k
= 0; k
< vector_active (match_vector
); k
++)
2126 struct cmd_token
*token
= vector_slot (match_vector
, k
);
2127 vector_set (matchvec
, token
);
2130 *status
= CMD_SUCCESS
;
2131 vector_set(matchvec
, &token_cr
);
2132 vector_free (cmd_vector
);
2133 cmd_matches_free(&matches
);
2134 cmd_describe_sort(matchvec
);
2138 ret
= is_cmd_ambiguous(cmd_vector
, command
, matches
, match
);
2141 vector_free (cmd_vector
);
2142 vector_free (matchvec
);
2143 cmd_matches_free(&matches
);
2144 *status
= CMD_ERR_AMBIGUOUS
;
2149 vector_free (cmd_vector
);
2150 vector_free (matchvec
);
2151 cmd_matches_free(&matches
);
2152 *status
= CMD_ERR_NO_MATCH
;
2157 /* Make description vector. */
2158 for (i
= 0; i
< vector_active (matches
); i
++) {
2159 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
&&
2160 !(cmd_element
->attr
== CMD_ATTR_DEPRECATED
||
2161 cmd_element
->attr
== CMD_ATTR_HIDDEN
))
2164 vector vline_trimmed
;
2167 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2168 if (last_word
== NULL
|| !strlen(last_word
))
2170 vline_trimmed
= vector_copy(vline
);
2171 vector_unset(vline_trimmed
, vector_active(vline_trimmed
) - 1);
2173 if (cmd_is_complete(cmd_element
, vline_trimmed
)
2174 && desc_unique_string(matchvec
, command_cr
))
2176 if (match
!= vararg_match
)
2177 vector_set(matchvec
, &token_cr
);
2180 vector_free(vline_trimmed
);
2183 match_vector
= vector_slot (matches
, i
);
2185 for (j
= 0; j
< vector_active(match_vector
); j
++)
2187 struct cmd_token
*token
= vector_slot(match_vector
, j
);
2190 string
= cmd_entry_function_desc(command
, token
);
2191 if (string
&& desc_unique_string(matchvec
, string
))
2192 vector_set(matchvec
, token
);
2198 * We can get into this situation when the command is complete
2199 * but the last part of the command is an optional piece of
2202 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2203 if (command_found
== 0 && (last_word
== NULL
|| !strlen(last_word
))) {
2204 vector_set(matchvec
, &token_cr
);
2207 vector_free (cmd_vector
);
2208 cmd_matches_free(&matches
);
2210 if (vector_slot (matchvec
, 0) == NULL
)
2212 vector_free (matchvec
);
2213 *status
= CMD_ERR_NO_MATCH
;
2217 *status
= CMD_SUCCESS
;
2218 cmd_describe_sort(matchvec
);
2223 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
2227 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2229 enum node_type onode
;
2230 vector shifted_vline
;
2234 vty
->node
= ENABLE_NODE
;
2235 /* We can try it on enable node, cos' the vty is authenticated */
2237 shifted_vline
= vector_init (vector_count(vline
));
2239 for (index
= 1; index
< vector_active (vline
); index
++)
2241 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2244 ret
= cmd_describe_command_real (shifted_vline
, vty
, status
);
2246 vector_free(shifted_vline
);
2252 return cmd_describe_command_real (vline
, vty
, status
);
2256 /* Check LCD of matched command. */
2258 cmd_lcd (char **matched
)
2266 if (matched
[0] == NULL
|| matched
[1] == NULL
)
2269 for (i
= 1; matched
[i
] != NULL
; i
++)
2271 s1
= matched
[i
- 1];
2274 for (j
= 0; (c1
= s1
[j
]) && (c2
= s2
[j
]); j
++)
2290 cmd_complete_cmp(const void *a
, const void *b
)
2292 const char *first
= *(char * const *)a
;
2293 const char *second
= *(char * const *)b
;
2304 return strcmp(first
, second
);
2308 cmd_complete_sort(vector matchvec
)
2310 qsort(matchvec
->index
, vector_active(matchvec
),
2311 sizeof(void*), cmd_complete_cmp
);
2314 /* Command line completion support. */
2316 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
, int islib
)
2319 vector cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2320 #define INIT_MATCHVEC_SIZE 10
2324 struct cmd_token
*token
;
2327 vector matches
= NULL
;
2328 vector match_vector
;
2330 if (vector_active (vline
) == 0)
2332 vector_free (cmd_vector
);
2333 *status
= CMD_ERR_NO_MATCH
;
2337 index
= vector_active (vline
) - 1;
2339 /* First, filter by command string */
2340 for (i
= 0; i
<= index
; i
++)
2342 command
= vector_slot (vline
, i
);
2343 enum match_type match
;
2347 cmd_matches_free(&matches
);
2349 /* First try completion match, if there is exactly match return 1 */
2350 ret
= cmd_vector_filter(cmd_vector
,
2356 if (ret
!= CMD_SUCCESS
)
2358 vector_free(cmd_vector
);
2359 cmd_matches_free(&matches
);
2364 /* Break here - the completion mustn't be checked to be non-ambiguous */
2368 /* If there is exact match then filter ambiguous match else check
2370 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2373 vector_free (cmd_vector
);
2374 cmd_matches_free(&matches
);
2375 *status
= CMD_ERR_AMBIGUOUS
;
2380 /* Prepare match vector. */
2381 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2383 /* Build the possible list of continuations into a list of completions */
2384 for (i
= 0; i
< vector_active (matches
); i
++)
2385 if ((match_vector
= vector_slot (matches
, i
)))
2390 for (j
= 0; j
< vector_active (match_vector
); j
++)
2391 if ((token
= vector_slot (match_vector
, j
)))
2393 string
= cmd_entry_function (vector_slot (vline
, index
),
2395 if (string
&& cmd_unique_string (matchvec
, string
))
2396 vector_set (matchvec
, (islib
!= 0 ?
2397 XSTRDUP (MTYPE_TMP
, string
) :
2398 strdup (string
) /* rl freed */));
2402 /* We don't need cmd_vector any more. */
2403 vector_free (cmd_vector
);
2404 cmd_matches_free(&matches
);
2406 /* No matched command */
2407 if (vector_slot (matchvec
, 0) == NULL
)
2409 vector_free (matchvec
);
2411 /* In case of 'command \t' pattern. Do you need '?' command at
2412 the end of the line. */
2413 if (vector_slot (vline
, index
) == '\0')
2414 *status
= CMD_ERR_NOTHING_TODO
;
2416 *status
= CMD_ERR_NO_MATCH
;
2420 /* Only one matched */
2421 if (vector_slot (matchvec
, 1) == NULL
)
2423 size_t index_size
= matchvec
->alloced
* sizeof (void *);
2424 match_str
= XMALLOC (MTYPE_TMP
, index_size
);
2425 memcpy (match_str
, matchvec
->index
, index_size
);
2426 vector_free (matchvec
);
2428 *status
= CMD_COMPLETE_FULL_MATCH
;
2431 /* Make it sure last element is NULL. */
2432 vector_set (matchvec
, NULL
);
2434 /* Check LCD of matched strings. */
2435 if (vector_slot (vline
, index
) != NULL
)
2437 lcd
= cmd_lcd ((char **) matchvec
->index
);
2441 int len
= strlen (vector_slot (vline
, index
));
2447 lcdstr
= (islib
!= 0 ?
2448 XMALLOC (MTYPE_TMP
, lcd
+ 1) :
2450 memcpy (lcdstr
, matchvec
->index
[0], lcd
);
2453 /* Free matchvec. */
2454 for (i
= 0; i
< vector_active (matchvec
); i
++)
2456 if (vector_slot (matchvec
, i
))
2459 XFREE (MTYPE_TMP
, vector_slot (matchvec
, i
));
2461 free (vector_slot (matchvec
, i
));
2464 vector_free (matchvec
);
2466 /* Make new matchvec. */
2467 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2468 vector_set (matchvec
, lcdstr
);
2470 size_t index_size
= matchvec
->alloced
* sizeof (void *);
2471 match_str
= XMALLOC (MTYPE_TMP
, index_size
);
2472 memcpy (match_str
, matchvec
->index
, index_size
);
2473 vector_free (matchvec
);
2475 *status
= CMD_COMPLETE_MATCH
;
2481 match_str
= (char **) matchvec
->index
;
2482 cmd_complete_sort(matchvec
);
2483 vector_only_wrapper_free (matchvec
);
2484 *status
= CMD_COMPLETE_LIST_MATCH
;
2489 cmd_complete_command_lib (vector vline
, struct vty
*vty
, int *status
, int islib
)
2493 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2495 enum node_type onode
;
2496 vector shifted_vline
;
2500 vty
->node
= ENABLE_NODE
;
2501 /* We can try it on enable node, cos' the vty is authenticated */
2503 shifted_vline
= vector_init (vector_count(vline
));
2505 for (index
= 1; index
< vector_active (vline
); index
++)
2507 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2510 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
, islib
);
2512 vector_free(shifted_vline
);
2517 return cmd_complete_command_real (vline
, vty
, status
, islib
);
2521 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
2523 return cmd_complete_command_lib (vline
, vty
, status
, 0);
2526 /* return parent node */
2527 /* MUST eventually converge on CONFIG_NODE */
2529 node_parent ( enum node_type node
)
2533 assert (node
> CONFIG_NODE
);
2537 case BGP_VPNV4_NODE
:
2538 case BGP_VPNV6_NODE
:
2539 case BGP_ENCAP_NODE
:
2540 case BGP_ENCAPV6_NODE
:
2542 case BGP_IPV4M_NODE
:
2544 case BGP_IPV6M_NODE
:
2547 case KEYCHAIN_KEY_NODE
:
2548 ret
= KEYCHAIN_NODE
;
2550 case LINK_PARAMS_NODE
:
2551 ret
= INTERFACE_NODE
;
2557 case LDP_IPV4_IFACE_NODE
:
2558 ret
= LDP_IPV4_NODE
;
2560 case LDP_IPV6_IFACE_NODE
:
2561 ret
= LDP_IPV6_NODE
;
2563 case LDP_PSEUDOWIRE_NODE
:
2564 ret
= LDP_L2VPN_NODE
;
2574 /* Execute command by argument vline vector. */
2576 cmd_execute_command_real (vector vline
,
2577 enum filter_type filter
,
2579 struct cmd_element
**cmd
)
2584 struct cmd_element
*cmd_element
;
2585 struct cmd_element
*matched_element
;
2586 unsigned int matched_count
, incomplete_count
;
2588 const char *argv
[CMD_ARGC_MAX
];
2589 enum match_type match
= 0;
2594 /* Make copy of command elements. */
2595 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2597 for (index
= 0; index
< vector_active (vline
); index
++)
2599 command
= vector_slot (vline
, index
);
2600 ret
= cmd_vector_filter(cmd_vector
,
2606 if (ret
!= CMD_SUCCESS
)
2608 cmd_matches_free(&matches
);
2612 if (match
== vararg_match
)
2614 cmd_matches_free(&matches
);
2618 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2619 cmd_matches_free(&matches
);
2623 vector_free(cmd_vector
);
2624 return CMD_ERR_AMBIGUOUS
;
2628 vector_free(cmd_vector
);
2629 return CMD_ERR_NO_MATCH
;
2633 /* Check matched count. */
2634 matched_element
= NULL
;
2636 incomplete_count
= 0;
2638 for (i
= 0; i
< vector_active (cmd_vector
); i
++)
2639 if ((cmd_element
= vector_slot (cmd_vector
, i
)))
2641 if (cmd_is_complete(cmd_element
, vline
))
2643 matched_element
= cmd_element
;
2652 /* Finish of using cmd_vector. */
2653 vector_free (cmd_vector
);
2655 /* To execute command, matched_count must be 1. */
2656 if (matched_count
== 0)
2658 if (incomplete_count
)
2659 return CMD_ERR_INCOMPLETE
;
2661 return CMD_ERR_NO_MATCH
;
2664 if (matched_count
> 1)
2665 return CMD_ERR_AMBIGUOUS
;
2667 ret
= cmd_parse(matched_element
, vline
, &argc
, argv
);
2668 if (ret
!= CMD_SUCCESS
)
2671 /* For vtysh execution. */
2673 *cmd
= matched_element
;
2675 if (matched_element
->daemon
)
2676 return CMD_SUCCESS_DAEMON
;
2678 /* Execute matched command. */
2679 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2683 * Execute a given command, handling things like "do ..." and checking
2684 * whether the given command might apply at a parent node if doesn't
2685 * apply for the current node.
2687 * @param vline Command line input, vector of char* where each element is
2689 * @param vty The vty context in which the command should be executed.
2690 * @param cmd Pointer where the struct cmd_element of the matched command
2691 * will be stored, if any. May be set to NULL if this info is
2693 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2694 * @return The status of the command that has been executed or an error code
2695 * as to why no command could be executed.
2698 cmd_execute_command (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
,
2700 int ret
, saved_ret
, tried
= 0;
2701 enum node_type onode
, try_node
;
2703 onode
= try_node
= vty
->node
;
2705 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2707 vector shifted_vline
;
2710 vty
->node
= ENABLE_NODE
;
2711 /* We can try it on enable node, cos' the vty is authenticated */
2713 shifted_vline
= vector_init (vector_count(vline
));
2715 for (index
= 1; index
< vector_active (vline
); index
++)
2717 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2720 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
2722 vector_free(shifted_vline
);
2728 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2733 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2734 while ( ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
2735 && vty
->node
> CONFIG_NODE
)
2737 try_node
= node_parent(try_node
);
2738 vty
->node
= try_node
;
2739 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2741 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
2743 /* succesfull command, leave the node as is */
2747 /* no command succeeded, reset the vty to the original node and
2748 return the error for this node */
2755 * Execute a given command, matching it strictly against the current node.
2756 * This mode is used when reading config files.
2758 * @param vline Command line input, vector of char* where each element is
2760 * @param vty The vty context in which the command should be executed.
2761 * @param cmd Pointer where the struct cmd_element* of the matched command
2762 * will be stored, if any. May be set to NULL if this info is
2764 * @return The status of the command that has been executed or an error code
2765 * as to why no command could be executed.
2768 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
2769 struct cmd_element
**cmd
)
2771 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
2775 * Parse one line of config, walking up the parse tree attempting to find a match
2777 * @param vty The vty context in which the command should be executed.
2778 * @param cmd Pointer where the struct cmd_element* of the match command
2779 * will be stored, if any. May be set to NULL if this info is
2781 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2783 * @return The status of the command that has been executed or an error code
2784 * as to why no command could be executed.
2787 command_config_read_one_line (struct vty
*vty
, struct cmd_element
**cmd
, int use_daemon
)
2793 vline
= cmd_make_strvec (vty
->buf
);
2795 /* In case of comment line */
2799 /* Execute configuration command : this is strict match */
2800 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2802 // Climb the tree and try the command again at each node
2803 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2804 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2805 ret
!= CMD_SUCCESS
&&
2806 ret
!= CMD_WARNING
&&
2807 vty
->node
!= CONFIG_NODE
) {
2809 saved_node
= vty
->node
;
2811 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2812 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2813 ret
!= CMD_SUCCESS
&&
2814 ret
!= CMD_WARNING
&&
2815 vty
->node
> CONFIG_NODE
) {
2816 vty
->node
= node_parent(vty
->node
);
2817 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2820 // If climbing the tree did not work then ignore the command and
2821 // stay at the same node
2822 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2823 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2824 ret
!= CMD_SUCCESS
&&
2827 vty
->node
= saved_node
;
2828 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
2832 cmd_free_strvec (vline
);
2837 /* Configuration make from file. */
2839 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
2841 int ret
, error_ret
=0;
2844 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
2849 ret
= command_config_read_one_line (vty
, NULL
, 0);
2851 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
2852 ret
!= CMD_ERR_NOTHING_TODO
)
2863 /* Configuration from terminal */
2864 DEFUN (config_terminal
,
2865 config_terminal_cmd
,
2866 "configure terminal",
2867 "Configuration from vty interface\n"
2868 "Configuration terminal\n")
2870 if (vty_config_lock (vty
))
2871 vty
->node
= CONFIG_NODE
;
2874 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
2880 /* Enable command */
2884 "Turn on privileged mode command\n")
2886 /* If enable password is NULL, change to ENABLE_NODE */
2887 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
2888 vty
->type
== VTY_SHELL_SERV
)
2889 vty
->node
= ENABLE_NODE
;
2891 vty
->node
= AUTH_ENABLE_NODE
;
2896 /* Disable command */
2900 "Turn off privileged mode command\n")
2902 if (vty
->node
== ENABLE_NODE
)
2903 vty
->node
= VIEW_NODE
;
2907 /* Down vty node level. */
2911 "Exit current mode and down to previous mode\n")
2917 case RESTRICTED_NODE
:
2918 if (vty_shell (vty
))
2921 vty
->status
= VTY_CLOSE
;
2924 vty
->node
= ENABLE_NODE
;
2925 vty_config_unlock (vty
);
2927 case INTERFACE_NODE
:
2937 case LDP_L2VPN_NODE
:
2944 vty
->node
= CONFIG_NODE
;
2947 case BGP_IPV4M_NODE
:
2948 case BGP_VPNV4_NODE
:
2949 case BGP_VPNV6_NODE
:
2950 case BGP_ENCAP_NODE
:
2951 case BGP_ENCAPV6_NODE
:
2953 case BGP_IPV6M_NODE
:
2954 vty
->node
= BGP_NODE
;
2958 vty
->node
= LDP_NODE
;
2960 case LDP_IPV4_IFACE_NODE
:
2961 vty
->node
= LDP_IPV4_NODE
;
2963 case LDP_IPV6_IFACE_NODE
:
2964 vty
->node
= LDP_IPV6_NODE
;
2966 case LDP_PSEUDOWIRE_NODE
:
2967 vty
->node
= LDP_L2VPN_NODE
;
2969 case KEYCHAIN_KEY_NODE
:
2970 vty
->node
= KEYCHAIN_NODE
;
2972 case LINK_PARAMS_NODE
:
2973 vty
->node
= INTERFACE_NODE
;
2981 /* quit is alias of exit. */
2985 "Exit current mode and down to previous mode\n")
2987 /* End of configuration. */
2991 "End current mode and change to enable mode.")
2997 case RESTRICTED_NODE
:
2998 /* Nothing to do. */
3001 case INTERFACE_NODE
:
3008 case BGP_ENCAP_NODE
:
3009 case BGP_ENCAPV6_NODE
:
3010 case BGP_VPNV4_NODE
:
3011 case BGP_VPNV6_NODE
:
3013 case BGP_IPV4M_NODE
:
3015 case BGP_IPV6M_NODE
:
3022 case LDP_IPV4_IFACE_NODE
:
3023 case LDP_IPV6_IFACE_NODE
:
3024 case LDP_L2VPN_NODE
:
3025 case LDP_PSEUDOWIRE_NODE
:
3028 case KEYCHAIN_KEY_NODE
:
3032 case LINK_PARAMS_NODE
:
3033 vty_config_unlock (vty
);
3034 vty
->node
= ENABLE_NODE
;
3043 DEFUN (show_version
,
3047 "Displays zebra version\n")
3049 vty_out (vty
, "Quagga %s (%s).%s", QUAGGA_VERSION
, host
.name
?host
.name
:"",
3051 vty_out (vty
, "%s%s%s", QUAGGA_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
3052 vty_out (vty
, "configured with:%s %s%s", VTY_NEWLINE
,
3053 QUAGGA_CONFIG_ARGS
, VTY_NEWLINE
);
3058 /* Help display function for all node. */
3062 "Description of the interactive help system\n")
3065 "Quagga VTY provides advanced help feature. When you need help,%s\
3066 anytime at the command line please press '?'.%s\
3068 If nothing matches, the help list will be empty and you must backup%s\
3069 until entering a '?' shows the available options.%s\
3070 Two styles of help are provided:%s\
3071 1. Full help is available when you are ready to enter a%s\
3072 command argument (e.g. 'show ?') and describes each possible%s\
3074 2. Partial help is provided when an abbreviated argument is entered%s\
3075 and you want to know what arguments match the input%s\
3076 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3077 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3078 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
3082 /* Help display function for all node. */
3086 "Print command list\n")
3089 struct cmd_node
*cnode
= vector_slot (cmdvec
, vty
->node
);
3090 struct cmd_element
*cmd
;
3092 for (i
= 0; i
< vector_active (cnode
->cmd_vector
); i
++)
3093 if ((cmd
= vector_slot (cnode
->cmd_vector
, i
)) != NULL
3094 && !(cmd
->attr
== CMD_ATTR_DEPRECATED
3095 || cmd
->attr
== CMD_ATTR_HIDDEN
))
3096 vty_out (vty
, " %s%s", cmd
->string
,
3101 /* Write current configuration into file. */
3102 DEFUN (config_write_file
,
3103 config_write_file_cmd
,
3105 "Write running configuration to memory, network, or terminal\n"
3106 "Write to configuration file\n")
3110 struct cmd_node
*node
;
3112 char *config_file_tmp
= NULL
;
3113 char *config_file_sav
= NULL
;
3114 int ret
= CMD_WARNING
;
3115 struct vty
*file_vty
;
3116 struct stat conf_stat
;
3118 /* Check and see if we are operating under vtysh configuration */
3119 if (host
.config
== NULL
)
3121 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
3127 config_file
= host
.config
;
3130 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
3131 strcpy (config_file_sav
, config_file
);
3132 strcat (config_file_sav
, CONF_BACKUP_EXT
);
3135 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
3136 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
3138 /* Open file to configuration write. */
3139 fd
= mkstemp (config_file_tmp
);
3142 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
3147 /* Make vty for configuration file. */
3148 file_vty
= vty_new ();
3150 file_vty
->type
= VTY_FILE
;
3152 /* Config file header print. */
3153 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
3154 vty_time_print (file_vty
, 1);
3155 vty_out (file_vty
, "!\n");
3157 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3158 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3160 if ((*node
->func
) (file_vty
))
3161 vty_out (file_vty
, "!\n");
3163 vty_close (file_vty
);
3165 if (stat(config_file
, &conf_stat
) >= 0)
3167 if (unlink (config_file_sav
) != 0)
3168 if (errno
!= ENOENT
)
3170 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
3174 if (link (config_file
, config_file_sav
) != 0)
3176 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
3181 if (unlink (config_file
) != 0)
3183 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
3188 if (link (config_file_tmp
, config_file
) != 0)
3190 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
3196 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
3198 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
3199 config_file
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
3203 vty_out (vty
, "Configuration saved to %s%s", config_file
,
3208 unlink (config_file_tmp
);
3209 XFREE (MTYPE_TMP
, config_file_tmp
);
3210 XFREE (MTYPE_TMP
, config_file_sav
);
3214 ALIAS (config_write_file
,
3217 "Write running configuration to memory, network, or terminal\n")
3219 ALIAS (config_write_file
,
3220 config_write_memory_cmd
,
3222 "Write running configuration to memory, network, or terminal\n"
3223 "Write configuration to the file (same as write file)\n")
3225 ALIAS (config_write_file
,
3226 copy_runningconfig_startupconfig_cmd
,
3227 "copy running-config startup-config",
3228 "Copy configuration\n"
3229 "Copy running config to... \n"
3230 "Copy running config to startup config (same as write file)\n")
3232 /* Write current configuration into the terminal. */
3233 DEFUN (config_write_terminal
,
3234 config_write_terminal_cmd
,
3236 "Write running configuration to memory, network, or terminal\n"
3237 "Write to terminal\n")
3240 struct cmd_node
*node
;
3242 if (vty
->type
== VTY_SHELL_SERV
)
3244 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3245 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
3247 if ((*node
->func
) (vty
))
3248 vty_out (vty
, "!%s", VTY_NEWLINE
);
3253 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
3255 vty_out (vty
, "!%s", VTY_NEWLINE
);
3257 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3258 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3260 if ((*node
->func
) (vty
))
3261 vty_out (vty
, "!%s", VTY_NEWLINE
);
3263 vty_out (vty
, "end%s",VTY_NEWLINE
);
3268 /* Write current configuration into the terminal. */
3269 ALIAS (config_write_terminal
,
3270 show_running_config_cmd
,
3271 "show running-config",
3273 "running configuration\n")
3275 /* Write startup configuration into the terminal. */
3276 DEFUN (show_startup_config
,
3277 show_startup_config_cmd
,
3278 "show startup-config",
3280 "Contentes of startup configuration\n")
3285 confp
= fopen (host
.config
, "r");
3288 vty_out (vty
, "Can't open configuration file [%s] due to '%s'%s",
3289 host
.config
, safe_strerror(errno
), VTY_NEWLINE
);
3293 while (fgets (buf
, BUFSIZ
, confp
))
3297 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
3301 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
3309 /* Hostname configuration */
3310 DEFUN (config_hostname
,
3313 "Set system's network name\n"
3314 "This system's network name\n")
3316 if (!isalpha((int) *argv
[0]))
3318 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
3323 XFREE (MTYPE_HOST
, host
.name
);
3325 host
.name
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3329 DEFUN (config_no_hostname
,
3331 "no hostname [HOSTNAME]",
3333 "Reset system's network name\n"
3334 "Host name of this router\n")
3337 XFREE (MTYPE_HOST
, host
.name
);
3342 /* VTY interface password set. */
3343 DEFUN (config_password
, password_cmd
,
3344 "password (8|) WORD",
3345 "Assign the terminal connection password\n"
3346 "Specifies a HIDDEN password will follow\n"
3348 "The HIDDEN line password string\n")
3350 /* Argument check. */
3353 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3359 if (*argv
[0] == '8')
3362 XFREE (MTYPE_HOST
, host
.password
);
3363 host
.password
= NULL
;
3364 if (host
.password_encrypt
)
3365 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3366 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3371 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3376 if (!isalnum ((int) *argv
[0]))
3379 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3384 XFREE (MTYPE_HOST
, host
.password
);
3385 host
.password
= NULL
;
3389 if (host
.password_encrypt
)
3390 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3391 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3394 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3399 ALIAS (config_password
, password_text_cmd
,
3401 "Assign the terminal connection password\n"
3402 "The UNENCRYPTED (cleartext) line password\n")
3404 /* VTY enable password set. */
3405 DEFUN (config_enable_password
, enable_password_cmd
,
3406 "enable password (8|) WORD",
3407 "Modify enable password parameters\n"
3408 "Assign the privileged level password\n"
3409 "Specifies a HIDDEN password will follow\n"
3411 "The HIDDEN 'enable' password string\n")
3413 /* Argument check. */
3416 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3420 /* Crypt type is specified. */
3423 if (*argv
[0] == '8')
3426 XFREE (MTYPE_HOST
, host
.enable
);
3429 if (host
.enable_encrypt
)
3430 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3431 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3437 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3442 if (!isalnum ((int) *argv
[0]))
3445 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3450 XFREE (MTYPE_HOST
, host
.enable
);
3453 /* Plain password input. */
3456 if (host
.enable_encrypt
)
3457 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3458 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3461 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3466 ALIAS (config_enable_password
,
3467 enable_password_text_cmd
,
3468 "enable password LINE",
3469 "Modify enable password parameters\n"
3470 "Assign the privileged level password\n"
3471 "The UNENCRYPTED (cleartext) 'enable' password\n")
3473 /* VTY enable password delete. */
3474 DEFUN (no_config_enable_password
, no_enable_password_cmd
,
3475 "no enable password",
3477 "Modify enable password parameters\n"
3478 "Assign the privileged level password\n")
3481 XFREE (MTYPE_HOST
, host
.enable
);
3484 if (host
.enable_encrypt
)
3485 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3486 host
.enable_encrypt
= NULL
;
3491 DEFUN (service_password_encrypt
,
3492 service_password_encrypt_cmd
,
3493 "service password-encryption",
3494 "Set up miscellaneous service\n"
3495 "Enable encrypted passwords\n")
3504 if (host
.password_encrypt
)
3505 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3506 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
3510 if (host
.enable_encrypt
)
3511 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3512 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
3518 DEFUN (no_service_password_encrypt
,
3519 no_service_password_encrypt_cmd
,
3520 "no service password-encryption",
3522 "Set up miscellaneous service\n"
3523 "Enable encrypted passwords\n")
3530 if (host
.password_encrypt
)
3531 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3532 host
.password_encrypt
= NULL
;
3534 if (host
.enable_encrypt
)
3535 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3536 host
.enable_encrypt
= NULL
;
3541 DEFUN (config_terminal_length
, config_terminal_length_cmd
,
3542 "terminal length <0-512>",
3543 "Set terminal line parameters\n"
3544 "Set number of lines on a screen\n"
3545 "Number of lines on screen (0 for no pausing)\n")
3548 char *endptr
= NULL
;
3550 lines
= strtol (argv
[0], &endptr
, 10);
3551 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3553 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3561 DEFUN (config_terminal_no_length
, config_terminal_no_length_cmd
,
3562 "terminal no length",
3563 "Set terminal line parameters\n"
3565 "Set number of lines on a screen\n")
3571 DEFUN (service_terminal_length
, service_terminal_length_cmd
,
3572 "service terminal-length <0-512>",
3573 "Set up miscellaneous service\n"
3574 "System wide terminal length configuration\n"
3575 "Number of lines of VTY (0 means no line control)\n")
3578 char *endptr
= NULL
;
3580 lines
= strtol (argv
[0], &endptr
, 10);
3581 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3583 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3591 DEFUN (no_service_terminal_length
, no_service_terminal_length_cmd
,
3592 "no service terminal-length [<0-512>]",
3594 "Set up miscellaneous service\n"
3595 "System wide terminal length configuration\n"
3596 "Number of lines of VTY (0 means no line control)\n")
3602 DEFUN_HIDDEN (do_echo
,
3605 "Echo a message back to the vty\n"
3606 "The message to echo\n")
3610 vty_out (vty
, "%s%s", ((message
= argv_concat(argv
, argc
, 0)) ? message
: ""),
3613 XFREE(MTYPE_TMP
, message
);
3617 DEFUN (config_logmsg
,
3619 "logmsg "LOG_LEVELS
" .MESSAGE",
3620 "Send a message to enabled logging destinations\n"
3622 "The message to send\n")
3627 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3628 return CMD_ERR_NO_MATCH
;
3630 zlog(NULL
, level
, "%s", ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
3632 XFREE(MTYPE_TMP
, message
);
3636 DEFUN (show_logging
,
3640 "Show current logging configuration\n")
3642 struct zlog
*zl
= zlog_default
;
3644 vty_out (vty
, "Syslog logging: ");
3645 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
3646 vty_out (vty
, "disabled");
3648 vty_out (vty
, "level %s, facility %s, ident %s",
3649 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
3650 facility_name(zl
->facility
), zl
->ident
);
3651 vty_out (vty
, "%s", VTY_NEWLINE
);
3653 vty_out (vty
, "Stdout logging: ");
3654 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
3655 vty_out (vty
, "disabled");
3657 vty_out (vty
, "level %s",
3658 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
3659 vty_out (vty
, "%s", VTY_NEWLINE
);
3661 vty_out (vty
, "Monitor logging: ");
3662 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
3663 vty_out (vty
, "disabled");
3665 vty_out (vty
, "level %s",
3666 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
3667 vty_out (vty
, "%s", VTY_NEWLINE
);
3669 vty_out (vty
, "File logging: ");
3670 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
3672 vty_out (vty
, "disabled");
3674 vty_out (vty
, "level %s, filename %s",
3675 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
3677 vty_out (vty
, "%s", VTY_NEWLINE
);
3679 vty_out (vty
, "Protocol name: %s%s",
3680 zlog_proto_names
[zl
->protocol
], VTY_NEWLINE
);
3681 vty_out (vty
, "Record priority: %s%s",
3682 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
3683 vty_out (vty
, "Timestamp precision: %d%s",
3684 zl
->timestamp_precision
, VTY_NEWLINE
);
3689 DEFUN (config_log_stdout
,
3690 config_log_stdout_cmd
,
3693 "Set stdout logging level\n")
3695 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
3699 DEFUN (config_log_stdout_level
,
3700 config_log_stdout_level_cmd
,
3701 "log stdout "LOG_LEVELS
,
3703 "Set stdout logging level\n"
3708 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3709 return CMD_ERR_NO_MATCH
;
3710 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, level
);
3714 DEFUN (no_config_log_stdout
,
3715 no_config_log_stdout_cmd
,
3716 "no log stdout [LEVEL]",
3719 "Cancel logging to stdout\n"
3722 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
3726 DEFUN (config_log_monitor
,
3727 config_log_monitor_cmd
,
3730 "Set terminal line (monitor) logging level\n")
3732 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
3736 DEFUN (config_log_monitor_level
,
3737 config_log_monitor_level_cmd
,
3738 "log monitor "LOG_LEVELS
,
3740 "Set terminal line (monitor) logging level\n"
3745 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3746 return CMD_ERR_NO_MATCH
;
3747 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, level
);
3751 DEFUN (no_config_log_monitor
,
3752 no_config_log_monitor_cmd
,
3753 "no log monitor [LEVEL]",
3756 "Disable terminal line (monitor) logging\n"
3759 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
3764 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
3768 const char *fullpath
;
3770 /* Path detection. */
3771 if (! IS_DIRECTORY_SEP (*fname
))
3773 char cwd
[MAXPATHLEN
+1];
3774 cwd
[MAXPATHLEN
] = '\0';
3776 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
3778 zlog_err ("config_log_file: Unable to alloc mem!");
3782 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
3785 zlog_err ("config_log_file: Unable to alloc mem!");
3788 sprintf (p
, "%s/%s", cwd
, fname
);
3794 ret
= zlog_set_file (NULL
, fullpath
, loglevel
);
3797 XFREE (MTYPE_TMP
, p
);
3801 vty_out (vty
, "can't open logfile %s\n", fname
);
3806 XFREE (MTYPE_HOST
, host
.logfile
);
3808 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
3810 #if defined(HAVE_CUMULUS)
3811 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
3812 zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] = ZLOG_DISABLED
;
3817 DEFUN (config_log_file
,
3818 config_log_file_cmd
,
3819 "log file FILENAME",
3822 "Logging filename\n")
3824 return set_log_file(vty
, argv
[0], zlog_default
->default_lvl
);
3827 DEFUN (config_log_file_level
,
3828 config_log_file_level_cmd
,
3829 "log file FILENAME "LOG_LEVELS
,
3832 "Logging filename\n"
3837 if ((level
= level_match(argv
[1])) == ZLOG_DISABLED
)
3838 return CMD_ERR_NO_MATCH
;
3839 return set_log_file(vty
, argv
[0], level
);
3842 DEFUN (no_config_log_file
,
3843 no_config_log_file_cmd
,
3844 "no log file [FILENAME]",
3847 "Cancel logging to file\n"
3848 "Logging file name\n")
3850 zlog_reset_file (NULL
);
3853 XFREE (MTYPE_HOST
, host
.logfile
);
3855 host
.logfile
= NULL
;
3860 ALIAS (no_config_log_file
,
3861 no_config_log_file_level_cmd
,
3862 "no log file FILENAME LEVEL",
3865 "Cancel logging to file\n"
3866 "Logging file name\n"
3869 DEFUN (config_log_syslog
,
3870 config_log_syslog_cmd
,
3873 "Set syslog logging level\n")
3875 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3879 DEFUN (config_log_syslog_level
,
3880 config_log_syslog_level_cmd
,
3881 "log syslog "LOG_LEVELS
,
3883 "Set syslog logging level\n"
3888 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3889 return CMD_ERR_NO_MATCH
;
3890 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, level
);
3894 DEFUN_DEPRECATED (config_log_syslog_facility
,
3895 config_log_syslog_facility_cmd
,
3896 "log syslog facility "LOG_FACILITIES
,
3898 "Logging goes to syslog\n"
3899 "(Deprecated) Facility parameter for syslog messages\n"
3904 if ((facility
= facility_match(argv
[0])) < 0)
3905 return CMD_ERR_NO_MATCH
;
3907 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3908 zlog_default
->facility
= facility
;
3912 DEFUN (no_config_log_syslog
,
3913 no_config_log_syslog_cmd
,
3914 "no log syslog [LEVEL]",
3917 "Cancel logging to syslog\n"
3920 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
3924 ALIAS (no_config_log_syslog
,
3925 no_config_log_syslog_facility_cmd
,
3926 "no log syslog facility "LOG_FACILITIES
,
3929 "Logging goes to syslog\n"
3930 "Facility parameter for syslog messages\n"
3933 DEFUN (config_log_facility
,
3934 config_log_facility_cmd
,
3935 "log facility "LOG_FACILITIES
,
3937 "Facility parameter for syslog messages\n"
3942 if ((facility
= facility_match(argv
[0])) < 0)
3943 return CMD_ERR_NO_MATCH
;
3944 zlog_default
->facility
= facility
;
3948 DEFUN (no_config_log_facility
,
3949 no_config_log_facility_cmd
,
3950 "no log facility [FACILITY]",
3953 "Reset syslog facility to default (daemon)\n"
3954 "Syslog facility\n")
3956 zlog_default
->facility
= LOG_DAEMON
;
3960 DEFUN_DEPRECATED (config_log_trap
,
3961 config_log_trap_cmd
,
3962 "log trap "LOG_LEVELS
,
3964 "(Deprecated) Set logging level and default for all destinations\n"
3970 if ((new_level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3971 return CMD_ERR_NO_MATCH
;
3973 zlog_default
->default_lvl
= new_level
;
3974 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
3975 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
3976 zlog_default
->maxlvl
[i
] = new_level
;
3980 DEFUN_DEPRECATED (no_config_log_trap
,
3981 no_config_log_trap_cmd
,
3982 "no log trap [LEVEL]",
3985 "Permit all logging information\n"
3988 zlog_default
->default_lvl
= LOG_DEBUG
;
3992 DEFUN (config_log_record_priority
,
3993 config_log_record_priority_cmd
,
3994 "log record-priority",
3996 "Log the priority of the message within the message\n")
3998 zlog_default
->record_priority
= 1 ;
4002 DEFUN (no_config_log_record_priority
,
4003 no_config_log_record_priority_cmd
,
4004 "no log record-priority",
4007 "Do not log the priority of the message within the message\n")
4009 zlog_default
->record_priority
= 0 ;
4013 DEFUN (config_log_timestamp_precision
,
4014 config_log_timestamp_precision_cmd
,
4015 "log timestamp precision <0-6>",
4017 "Timestamp configuration\n"
4018 "Set the timestamp precision\n"
4019 "Number of subsecond digits\n")
4023 vty_out (vty
, "Insufficient arguments%s", VTY_NEWLINE
);
4027 VTY_GET_INTEGER_RANGE("Timestamp Precision",
4028 zlog_default
->timestamp_precision
, argv
[0], 0, 6);
4032 DEFUN (no_config_log_timestamp_precision
,
4033 no_config_log_timestamp_precision_cmd
,
4034 "no log timestamp precision",
4037 "Timestamp configuration\n"
4038 "Reset the timestamp precision to the default value of 0\n")
4040 zlog_default
->timestamp_precision
= 0 ;
4045 cmd_banner_motd_file (const char *file
)
4047 int success
= CMD_SUCCESS
;
4052 rpath
= realpath (file
, p
);
4054 return CMD_ERR_NO_FILE
;
4055 in
= strstr (rpath
, SYSCONFDIR
);
4059 XFREE (MTYPE_HOST
, host
.motdfile
);
4060 host
.motdfile
= XSTRDUP (MTYPE_HOST
, file
);
4063 success
= CMD_WARNING
;
4068 DEFUN (banner_motd_file
,
4069 banner_motd_file_cmd
,
4070 "banner motd file FILE",
4073 "Banner from a file\n"
4076 int cmd
= cmd_banner_motd_file (argv
[0]);
4078 if (cmd
== CMD_ERR_NO_FILE
)
4079 vty_out (vty
, "%s does not exist", argv
[0]);
4080 else if (cmd
== CMD_WARNING
)
4081 vty_out (vty
, "%s must be in %s",
4082 argv
[0], SYSCONFDIR
);
4087 DEFUN (banner_motd_default
,
4088 banner_motd_default_cmd
,
4089 "banner motd default",
4090 "Set banner string\n"
4091 "Strings for motd\n"
4094 host
.motd
= default_motd
;
4098 DEFUN (no_banner_motd
,
4102 "Set banner string\n"
4103 "Strings for motd\n")
4107 XFREE (MTYPE_HOST
, host
.motdfile
);
4108 host
.motdfile
= NULL
;
4112 DEFUN (show_commandtree
,
4113 show_commandtree_cmd
,
4116 "Show command tree\n")
4122 vty_out (vty
, "Current node id: %d%s", vty
->node
, VTY_NEWLINE
);
4124 /* vector of all commands installed at this node */
4125 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
4127 /* loop over all commands at this node */
4128 for (i
= 0; i
< vector_active(cmd_vector
); ++i
)
4130 struct cmd_element
*cmd_element
;
4132 /* A cmd_element (seems to be) is an individual command */
4133 if ((cmd_element
= vector_slot (cmd_vector
, i
)) == NULL
)
4136 vty_out (vty
, " %s%s", cmd_element
->string
, VTY_NEWLINE
);
4139 vector_free (cmd_vector
);
4143 /* Set config filename. Called from vty.c */
4145 host_config_set (const char *filename
)
4148 XFREE (MTYPE_HOST
, host
.config
);
4149 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
4153 install_default (enum node_type node
)
4155 install_element (node
, &config_exit_cmd
);
4156 install_element (node
, &config_quit_cmd
);
4157 install_element (node
, &config_end_cmd
);
4158 install_element (node
, &config_help_cmd
);
4159 install_element (node
, &config_list_cmd
);
4161 install_element (node
, &config_write_terminal_cmd
);
4162 install_element (node
, &config_write_file_cmd
);
4163 install_element (node
, &config_write_memory_cmd
);
4164 install_element (node
, &config_write_cmd
);
4165 install_element (node
, &show_running_config_cmd
);
4168 /* Initialize command interface. Install basic nodes and commands. */
4170 cmd_init (int terminal
)
4172 command_cr
= XSTRDUP(MTYPE_CMD_TOKENS
, "<cr>");
4173 token_cr
.type
= TOKEN_TERMINAL
;
4174 token_cr
.terminal
= TERMINAL_LITERAL
;
4175 token_cr
.cmd
= command_cr
;
4176 token_cr
.desc
= XSTRDUP(MTYPE_CMD_TOKENS
, "");
4178 /* Allocate initial top vector of commands. */
4179 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
4181 /* Default host value settings. */
4183 host
.password
= NULL
;
4185 host
.logfile
= NULL
;
4188 host
.motd
= default_motd
;
4189 host
.motdfile
= NULL
;
4191 /* Install top nodes. */
4192 install_node (&view_node
, NULL
);
4193 install_node (&enable_node
, NULL
);
4194 install_node (&auth_node
, NULL
);
4195 install_node (&auth_enable_node
, NULL
);
4196 install_node (&restricted_node
, NULL
);
4197 install_node (&config_node
, config_write_host
);
4199 /* Each node's basic commands. */
4200 install_element (VIEW_NODE
, &show_version_cmd
);
4203 install_element (VIEW_NODE
, &config_list_cmd
);
4204 install_element (VIEW_NODE
, &config_exit_cmd
);
4205 install_element (VIEW_NODE
, &config_quit_cmd
);
4206 install_element (VIEW_NODE
, &config_help_cmd
);
4207 install_element (VIEW_NODE
, &config_enable_cmd
);
4208 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
4209 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
4210 install_element (VIEW_NODE
, &show_logging_cmd
);
4211 install_element (VIEW_NODE
, &show_commandtree_cmd
);
4212 install_element (VIEW_NODE
, &echo_cmd
);
4214 install_element (RESTRICTED_NODE
, &config_list_cmd
);
4215 install_element (RESTRICTED_NODE
, &config_exit_cmd
);
4216 install_element (RESTRICTED_NODE
, &config_quit_cmd
);
4217 install_element (RESTRICTED_NODE
, &config_help_cmd
);
4218 install_element (RESTRICTED_NODE
, &config_enable_cmd
);
4219 install_element (RESTRICTED_NODE
, &config_terminal_length_cmd
);
4220 install_element (RESTRICTED_NODE
, &config_terminal_no_length_cmd
);
4221 install_element (RESTRICTED_NODE
, &echo_cmd
);
4226 install_default (ENABLE_NODE
);
4227 install_element (ENABLE_NODE
, &config_disable_cmd
);
4228 install_element (ENABLE_NODE
, &config_terminal_cmd
);
4229 install_element (ENABLE_NODE
, ©_runningconfig_startupconfig_cmd
);
4231 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
4232 install_element (ENABLE_NODE
, &show_version_cmd
);
4233 install_element (ENABLE_NODE
, &show_commandtree_cmd
);
4237 install_element (ENABLE_NODE
, &config_terminal_length_cmd
);
4238 install_element (ENABLE_NODE
, &config_terminal_no_length_cmd
);
4239 install_element (ENABLE_NODE
, &show_logging_cmd
);
4240 install_element (ENABLE_NODE
, &echo_cmd
);
4241 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
4243 install_default (CONFIG_NODE
);
4246 install_element (CONFIG_NODE
, &hostname_cmd
);
4247 install_element (CONFIG_NODE
, &no_hostname_cmd
);
4251 install_element (CONFIG_NODE
, &password_cmd
);
4252 install_element (CONFIG_NODE
, &password_text_cmd
);
4253 install_element (CONFIG_NODE
, &enable_password_cmd
);
4254 install_element (CONFIG_NODE
, &enable_password_text_cmd
);
4255 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
4257 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
4258 install_element (CONFIG_NODE
, &config_log_stdout_level_cmd
);
4259 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
4260 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
4261 install_element (CONFIG_NODE
, &config_log_monitor_level_cmd
);
4262 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
4263 install_element (CONFIG_NODE
, &config_log_file_cmd
);
4264 install_element (CONFIG_NODE
, &config_log_file_level_cmd
);
4265 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
4266 install_element (CONFIG_NODE
, &no_config_log_file_level_cmd
);
4267 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
4268 install_element (CONFIG_NODE
, &config_log_syslog_level_cmd
);
4269 install_element (CONFIG_NODE
, &config_log_syslog_facility_cmd
);
4270 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
4271 install_element (CONFIG_NODE
, &no_config_log_syslog_facility_cmd
);
4272 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
4273 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
4274 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
4275 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
4276 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
4277 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
4278 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
4279 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
4280 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
4281 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
4282 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
4283 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
4284 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
4285 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
4286 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
4288 install_element (VIEW_NODE
, &show_thread_cpu_cmd
);
4289 install_element (ENABLE_NODE
, &show_thread_cpu_cmd
);
4290 install_element (RESTRICTED_NODE
, &show_thread_cpu_cmd
);
4292 install_element (ENABLE_NODE
, &clear_thread_cpu_cmd
);
4293 install_element (VIEW_NODE
, &show_work_queues_cmd
);
4294 install_element (ENABLE_NODE
, &show_work_queues_cmd
);
4296 vrf_install_commands ();
4298 srandom(time(NULL
));
4302 cmd_terminate_token(struct cmd_token
*token
)
4305 vector keyword_vect
;
4307 if (token
->multiple
)
4309 for (i
= 0; i
< vector_active(token
->multiple
); i
++)
4310 cmd_terminate_token(vector_slot(token
->multiple
, i
));
4311 vector_free(token
->multiple
);
4312 token
->multiple
= NULL
;
4317 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
4319 keyword_vect
= vector_slot(token
->keyword
, i
);
4320 for (j
= 0; j
< vector_active(keyword_vect
); j
++)
4321 cmd_terminate_token(vector_slot(keyword_vect
, j
));
4322 vector_free(keyword_vect
);
4324 vector_free(token
->keyword
);
4325 token
->keyword
= NULL
;
4328 XFREE(MTYPE_CMD_TOKENS
, token
->cmd
);
4329 XFREE(MTYPE_CMD_TOKENS
, token
->desc
);
4331 XFREE(MTYPE_CMD_TOKENS
, token
);
4335 cmd_terminate_element(struct cmd_element
*cmd
)
4339 if (cmd
->tokens
== NULL
)
4342 for (i
= 0; i
< vector_active(cmd
->tokens
); i
++)
4343 cmd_terminate_token(vector_slot(cmd
->tokens
, i
));
4345 vector_free(cmd
->tokens
);
4353 struct cmd_node
*cmd_node
;
4354 struct cmd_element
*cmd_element
;
4359 for (i
= 0; i
< vector_active (cmdvec
); i
++)
4360 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
4362 cmd_node_v
= cmd_node
->cmd_vector
;
4364 for (j
= 0; j
< vector_active (cmd_node_v
); j
++)
4365 if ((cmd_element
= vector_slot (cmd_node_v
, j
)) != NULL
)
4366 cmd_terminate_element(cmd_element
);
4368 vector_free (cmd_node_v
);
4371 vector_free (cmdvec
);
4376 XFREE(MTYPE_CMD_TOKENS
, command_cr
);
4378 XFREE(MTYPE_CMD_TOKENS
, token_cr
.desc
);
4380 XFREE (MTYPE_HOST
, host
.name
);
4382 XFREE (MTYPE_HOST
, host
.password
);
4383 if (host
.password_encrypt
)
4384 XFREE (MTYPE_HOST
, host
.password_encrypt
);
4386 XFREE (MTYPE_HOST
, host
.enable
);
4387 if (host
.enable_encrypt
)
4388 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
4390 XFREE (MTYPE_HOST
, host
.logfile
);
4392 XFREE (MTYPE_HOST
, host
.motdfile
);
4394 XFREE (MTYPE_HOST
, host
.config
);