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"
36 /* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
40 struct cmd_token token_cr
;
41 char *command_cr
= NULL
;
56 MATCHER_EXCEED_ARGC_MAX
59 #define MATCHER_ERROR(matcher_rv) \
60 ( (matcher_rv) == MATCHER_INCOMPLETE \
61 || (matcher_rv) == MATCHER_NO_MATCH \
62 || (matcher_rv) == MATCHER_AMBIGUOUS \
63 || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
66 /* Host information structure. */
69 /* Standard command node structures. */
70 static struct cmd_node auth_node
=
76 static struct cmd_node view_node
=
82 static struct cmd_node restricted_node
=
88 static struct cmd_node auth_enable_node
=
94 static struct cmd_node enable_node
=
100 static struct cmd_node config_node
=
107 /* Default motd string. */
108 static const char *default_motd
=
110 Hello, this is " QUAGGA_PROGNAME
" (version " QUAGGA_VERSION
").\r\n\
111 " QUAGGA_COPYRIGHT
"\r\n\
115 static const struct facility_map
{
119 } syslog_facilities
[] =
121 { LOG_KERN
, "kern", 1 },
122 { LOG_USER
, "user", 2 },
123 { LOG_MAIL
, "mail", 1 },
124 { LOG_DAEMON
, "daemon", 1 },
125 { LOG_AUTH
, "auth", 1 },
126 { LOG_SYSLOG
, "syslog", 1 },
127 { LOG_LPR
, "lpr", 2 },
128 { LOG_NEWS
, "news", 1 },
129 { LOG_UUCP
, "uucp", 2 },
130 { LOG_CRON
, "cron", 1 },
132 { LOG_FTP
, "ftp", 1 },
134 { LOG_LOCAL0
, "local0", 6 },
135 { LOG_LOCAL1
, "local1", 6 },
136 { LOG_LOCAL2
, "local2", 6 },
137 { LOG_LOCAL3
, "local3", 6 },
138 { LOG_LOCAL4
, "local4", 6 },
139 { LOG_LOCAL5
, "local5", 6 },
140 { LOG_LOCAL6
, "local6", 6 },
141 { LOG_LOCAL7
, "local7", 6 },
146 facility_name(int facility
)
148 const struct facility_map
*fm
;
150 for (fm
= syslog_facilities
; fm
->name
; fm
++)
151 if (fm
->facility
== facility
)
157 facility_match(const char *str
)
159 const struct facility_map
*fm
;
161 for (fm
= syslog_facilities
; fm
->name
; fm
++)
162 if (!strncmp(str
,fm
->name
,fm
->match
))
168 level_match(const char *s
)
172 for ( level
= 0 ; zlog_priority
[level
] != NULL
; level
++ )
173 if (!strncmp (s
, zlog_priority
[level
], 2))
175 return ZLOG_DISABLED
;
178 /* This is called from main when a daemon is invoked with -v or --version. */
180 print_version (const char *progname
)
182 printf ("%s version %s\n", progname
, QUAGGA_VERSION
);
183 printf ("%s\n", QUAGGA_COPYRIGHT
);
187 /* Utility function to concatenate argv argument into a single string
188 with inserting ' ' character between each argument. */
190 argv_concat (const char **argv
, int argc
, int shift
)
198 for (i
= shift
; i
< argc
; i
++)
199 len
+= strlen(argv
[i
])+1;
202 p
= str
= XMALLOC(MTYPE_TMP
, len
);
203 for (i
= shift
; i
< argc
; i
++)
206 memcpy(p
, argv
[i
], (arglen
= strlen(argv
[i
])));
214 /* Install top node of command vector. */
216 install_node (struct cmd_node
*node
,
217 int (*func
) (struct vty
*))
219 vector_set_index (cmdvec
, node
->node
, node
);
221 node
->cmd_vector
= vector_init (VECTOR_MIN_SIZE
);
224 /* Breaking up string into each command piece. I assume given
225 character is separated by a space character. Return value is a
226 vector which includes char ** data element. */
228 cmd_make_strvec (const char *string
)
230 const char *cp
, *start
;
240 /* Skip white spaces. */
241 while (isspace ((int) *cp
) && *cp
!= '\0')
244 /* Return if there is only white spaces */
248 if (*cp
== '!' || *cp
== '#')
251 /* Prepare return vector. */
252 strvec
= vector_init (VECTOR_MIN_SIZE
);
254 /* Copy each command piece and set into vector. */
258 while (!(isspace ((int) *cp
) || *cp
== '\r' || *cp
== '\n') &&
262 token
= XMALLOC (MTYPE_STRVEC
, strlen
+ 1);
263 memcpy (token
, start
, strlen
);
264 *(token
+ strlen
) = '\0';
265 vector_set (strvec
, token
);
267 while ((isspace ((int) *cp
) || *cp
== '\n' || *cp
== '\r') &&
276 /* Free allocated string vector. */
278 cmd_free_strvec (vector v
)
286 for (i
= 0; i
< vector_active (v
); i
++)
287 if ((cp
= vector_slot (v
, i
)) != NULL
)
288 XFREE (MTYPE_STRVEC
, cp
);
293 struct format_parser_state
295 vector topvect
; /* Top level vector */
296 vector intvect
; /* Intermediate level vector, used when there's
297 * a multiple in a keyword. */
298 vector curvect
; /* current vector where read tokens should be
301 const char *string
; /* pointer to command string, not modified */
302 const char *cp
; /* pointer in command string, moved along while
304 const char *dp
; /* pointer in description string, moved along while
307 int in_keyword
; /* flag to remember if we are in a keyword group */
308 int in_multiple
; /* flag to remember if we are in a multiple group */
309 int just_read_word
; /* flag to remember if the last thing we red was a
310 * real word and not some abstract token */
314 format_parser_error(struct format_parser_state
*state
, const char *message
)
316 int offset
= state
->cp
- state
->string
+ 1;
318 fprintf(stderr
, "\nError parsing command: \"%s\"\n", state
->string
);
319 fprintf(stderr
, " %*c\n", offset
, '^');
320 fprintf(stderr
, "%s at offset %d.\n", message
, offset
);
321 fprintf(stderr
, "This is a programming error. Check your DEFUNs etc.\n");
326 format_parser_desc_str(struct format_parser_state
*state
)
328 const char *cp
, *start
;
337 /* Skip white spaces. */
338 while (isspace ((int) *cp
) && *cp
!= '\0')
341 /* Return if there is only white spaces */
347 while (!(*cp
== '\r' || *cp
== '\n') && *cp
!= '\0')
351 token
= XMALLOC (MTYPE_CMD_TOKENS
, strlen
+ 1);
352 memcpy (token
, start
, strlen
);
353 *(token
+ strlen
) = '\0';
361 format_parser_begin_keyword(struct format_parser_state
*state
)
363 struct cmd_token
*token
;
366 if (state
->in_keyword
367 || state
->in_multiple
)
368 format_parser_error(state
, "Unexpected '{'");
371 state
->in_keyword
= 1;
373 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
374 token
->type
= TOKEN_KEYWORD
;
375 token
->keyword
= vector_init(VECTOR_MIN_SIZE
);
377 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
378 vector_set(token
->keyword
, keyword_vect
);
380 vector_set(state
->curvect
, token
);
381 state
->curvect
= keyword_vect
;
385 format_parser_begin_multiple(struct format_parser_state
*state
)
387 struct cmd_token
*token
;
389 if (state
->in_keyword
== 1)
390 format_parser_error(state
, "Keyword starting with '('");
392 if (state
->in_multiple
)
393 format_parser_error(state
, "Nested group");
396 state
->in_multiple
= 1;
397 state
->just_read_word
= 0;
399 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
400 token
->type
= TOKEN_MULTIPLE
;
401 token
->multiple
= vector_init(VECTOR_MIN_SIZE
);
403 vector_set(state
->curvect
, token
);
404 if (state
->curvect
!= state
->topvect
)
405 state
->intvect
= state
->curvect
;
406 state
->curvect
= token
->multiple
;
410 format_parser_end_keyword(struct format_parser_state
*state
)
412 if (state
->in_multiple
413 || !state
->in_keyword
)
414 format_parser_error(state
, "Unexpected '}'");
416 if (state
->in_keyword
== 1)
417 format_parser_error(state
, "Empty keyword group");
420 state
->in_keyword
= 0;
421 state
->curvect
= state
->topvect
;
425 format_parser_end_multiple(struct format_parser_state
*state
)
429 if (!state
->in_multiple
)
430 format_parser_error(state
, "Unepexted ')'");
432 if (vector_active(state
->curvect
) == 0)
433 format_parser_error(state
, "Empty multiple section");
435 if (!state
->just_read_word
)
437 /* There are constructions like
438 * 'show ip ospf database ... (self-originate|)'
440 * The old parser reads a description string for the
441 * word '' between |) which will never match.
442 * Simulate this behvaior by dropping the next desc
443 * string in such a case. */
445 dummy
= format_parser_desc_str(state
);
446 XFREE(MTYPE_CMD_TOKENS
, dummy
);
450 state
->in_multiple
= 0;
453 state
->curvect
= state
->intvect
;
455 state
->curvect
= state
->topvect
;
459 format_parser_handle_pipe(struct format_parser_state
*state
)
461 struct cmd_token
*keyword_token
;
464 if (state
->in_multiple
)
466 state
->just_read_word
= 0;
469 else if (state
->in_keyword
)
471 state
->in_keyword
= 1;
474 keyword_token
= vector_slot(state
->topvect
,
475 vector_active(state
->topvect
) - 1);
476 keyword_vect
= vector_init(VECTOR_MIN_SIZE
);
477 vector_set(keyword_token
->keyword
, keyword_vect
);
478 state
->curvect
= keyword_vect
;
482 format_parser_error(state
, "Unexpected '|'");
487 format_parser_read_word(struct format_parser_state
*state
)
492 struct cmd_token
*token
;
496 while (state
->cp
[0] != '\0'
497 && !strchr("\r\n(){}|", state
->cp
[0])
498 && !isspace((int)state
->cp
[0]))
501 len
= state
->cp
- start
;
502 cmd
= XMALLOC(MTYPE_CMD_TOKENS
, len
+ 1);
503 memcpy(cmd
, start
, len
);
506 token
= XCALLOC(MTYPE_CMD_TOKENS
, sizeof(*token
));
507 token
->type
= TOKEN_TERMINAL
;
509 token
->desc
= format_parser_desc_str(state
);
510 vector_set(state
->curvect
, token
);
512 if (state
->in_keyword
== 1)
513 state
->in_keyword
= 2;
515 state
->just_read_word
= 1;
519 * Parse a given command format string and build a tree of tokens from
520 * it that is suitable to be used by the command subsystem.
522 * @param string Command format string.
523 * @param descstr Description string.
524 * @return A vector of struct cmd_token representing the given command,
528 cmd_parse_format(const char *string
, const char *descstr
)
530 struct format_parser_state state
;
535 memset(&state
, 0, sizeof(state
));
536 state
.topvect
= state
.curvect
= vector_init(VECTOR_MIN_SIZE
);
537 state
.cp
= state
.string
= string
;
542 while (isspace((int)state
.cp
[0]) && state
.cp
[0] != '\0')
549 || state
.in_multiple
)
550 format_parser_error(&state
, "Unclosed group/keyword");
551 return state
.topvect
;
553 format_parser_begin_keyword(&state
);
556 format_parser_begin_multiple(&state
);
559 format_parser_end_keyword(&state
);
562 format_parser_end_multiple(&state
);
565 format_parser_handle_pipe(&state
);
568 format_parser_read_word(&state
);
573 /* Return prompt character of specified node. */
575 cmd_prompt (enum node_type node
)
577 struct cmd_node
*cnode
;
579 cnode
= vector_slot (cmdvec
, node
);
580 return cnode
->prompt
;
583 /* Install a command into a node. */
585 install_element (enum node_type ntype
, struct cmd_element
*cmd
)
587 struct cmd_node
*cnode
;
589 /* cmd_init hasn't been called */
593 cnode
= vector_slot (cmdvec
, ntype
);
597 fprintf (stderr
, "Command node %d doesn't exist, please check it\n",
602 vector_set (cnode
->cmd_vector
, cmd
);
603 if (cmd
->tokens
== NULL
)
604 cmd
->tokens
= cmd_parse_format(cmd
->string
, cmd
->doc
);
607 static const unsigned char itoa64
[] =
608 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
611 to64(char *s
, long v
, int n
)
615 *s
++ = itoa64
[v
&0x3f];
621 zencrypt (const char *passwd
)
625 char *crypt (const char *, const char *);
629 to64(&salt
[0], random(), 3);
630 to64(&salt
[3], tv
.tv_usec
, 3);
633 return crypt (passwd
, salt
);
636 /* This function write configuration of this host. */
638 config_write_host (struct vty
*vty
)
641 vty_out (vty
, "hostname %s%s", host
.name
, VTY_NEWLINE
);
645 if (host
.password_encrypt
)
646 vty_out (vty
, "password 8 %s%s", host
.password_encrypt
, VTY_NEWLINE
);
647 if (host
.enable_encrypt
)
648 vty_out (vty
, "enable password 8 %s%s", host
.enable_encrypt
, VTY_NEWLINE
);
653 vty_out (vty
, "password %s%s", host
.password
, VTY_NEWLINE
);
655 vty_out (vty
, "enable password %s%s", host
.enable
, VTY_NEWLINE
);
658 if (zlog_default
->default_lvl
!= LOG_DEBUG
)
660 vty_out (vty
, "! N.B. The 'log trap' command is deprecated.%s",
662 vty_out (vty
, "log trap %s%s",
663 zlog_priority
[zlog_default
->default_lvl
], VTY_NEWLINE
);
666 if (host
.logfile
&& (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != ZLOG_DISABLED
))
668 vty_out (vty
, "log file %s", host
.logfile
);
669 if (zlog_default
->maxlvl
[ZLOG_DEST_FILE
] != zlog_default
->default_lvl
)
671 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_FILE
]]);
672 vty_out (vty
, "%s", VTY_NEWLINE
);
675 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != ZLOG_DISABLED
)
677 vty_out (vty
, "log stdout");
678 if (zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
] != zlog_default
->default_lvl
)
680 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_STDOUT
]]);
681 vty_out (vty
, "%s", VTY_NEWLINE
);
684 if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
685 vty_out(vty
,"no log monitor%s",VTY_NEWLINE
);
686 else if (zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
] != zlog_default
->default_lvl
)
687 vty_out(vty
,"log monitor %s%s",
688 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_MONITOR
]],VTY_NEWLINE
);
690 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != ZLOG_DISABLED
)
692 vty_out (vty
, "log syslog");
693 if (zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
] != zlog_default
->default_lvl
)
695 zlog_priority
[zlog_default
->maxlvl
[ZLOG_DEST_SYSLOG
]]);
696 vty_out (vty
, "%s", VTY_NEWLINE
);
699 if (zlog_default
->facility
!= LOG_DAEMON
)
700 vty_out (vty
, "log facility %s%s",
701 facility_name(zlog_default
->facility
), VTY_NEWLINE
);
703 if (zlog_default
->record_priority
== 1)
704 vty_out (vty
, "log record-priority%s", VTY_NEWLINE
);
706 if (zlog_default
->timestamp_precision
> 0)
707 vty_out (vty
, "log timestamp precision %d%s",
708 zlog_default
->timestamp_precision
, VTY_NEWLINE
);
711 vty_out (vty
, "service advanced-vty%s", VTY_NEWLINE
);
714 vty_out (vty
, "service password-encryption%s", VTY_NEWLINE
);
717 vty_out (vty
, "service terminal-length %d%s", host
.lines
,
721 vty_out (vty
, "banner motd file %s%s", host
.motdfile
, VTY_NEWLINE
);
722 else if (! host
.motd
)
723 vty_out (vty
, "no banner motd%s", VTY_NEWLINE
);
728 /* Utility function for getting command vector. */
730 cmd_node_vector (vector v
, enum node_type ntype
)
732 struct cmd_node
*cnode
= vector_slot (v
, ntype
);
733 return cnode
->cmd_vector
;
737 /* Filter command vector by symbol. This function is not actually used;
738 * should it be deleted? */
740 cmd_filter_by_symbol (char *command
, char *symbol
)
744 if (strcmp (symbol
, "IPV4_ADDRESS") == 0)
747 lim
= strlen (command
);
750 if (! (isdigit ((int) command
[i
]) || command
[i
] == '.' || command
[i
] == '/'))
756 if (strcmp (symbol
, "STRING") == 0)
759 lim
= strlen (command
);
762 if (! (isalpha ((int) command
[i
]) || command
[i
] == '_' || command
[i
] == '-'))
768 if (strcmp (symbol
, "IFNAME") == 0)
771 lim
= strlen (command
);
774 if (! isalnum ((int) command
[i
]))
784 /* Completion match types. */
799 static enum match_type
800 cmd_ipv4_match (const char *str
)
803 int dots
= 0, nums
= 0;
811 memset (buf
, 0, sizeof (buf
));
820 if (*(str
+ 1) == '.')
823 if (*(str
+ 1) == '\0')
829 if (!isdigit ((int) *str
))
838 strncpy (buf
, sp
, str
- sp
);
839 if (atoi (buf
) > 255)
856 static enum match_type
857 cmd_ipv4_prefix_match (const char *str
)
868 memset (buf
, 0, sizeof (buf
));
870 while (*str
!= '\0' && *str
!= '/')
877 if (*(str
+ 1) == '.' || *(str
+ 1) == '/')
880 if (*(str
+ 1) == '\0')
887 if (!isdigit ((int) *str
))
896 strncpy (buf
, sp
, str
- sp
);
897 if (atoi (buf
) > 255)
904 if (*(str
+ 1) == '\0')
910 else if (*str
== '\0')
923 if (!isdigit ((int) *str
))
935 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
936 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
937 #define STATE_START 1
938 #define STATE_COLON 2
939 #define STATE_DOUBLE 3
942 #define STATE_SLASH 6
947 static enum match_type
948 cmd_ipv6_match (const char *str
)
950 struct sockaddr_in6 sin6_dummy
;
956 if (strspn (str
, IPV6_ADDR_STR
) != strlen (str
))
959 /* use inet_pton that has a better support,
960 * for example inet_pton can support the automatic addresses:
963 ret
= inet_pton(AF_INET6
, str
, &sin6_dummy
.sin6_addr
);
971 static enum match_type
972 cmd_ipv6_prefix_match (const char *str
)
974 int state
= STATE_START
;
975 int colons
= 0, nums
= 0, double_colon
= 0;
977 const char *sp
= NULL
;
983 if (strspn (str
, IPV6_PREFIX_STR
) != strlen (str
))
986 while (*str
!= '\0' && state
!= STATE_MASK
)
993 if (*(str
+ 1) != ':' && *(str
+ 1) != '\0')
1007 if (*(str
+ 1) == '/')
1009 else if (*(str
+ 1) == ':')
1010 state
= STATE_DOUBLE
;
1021 if (*(str
+ 1) == ':')
1025 if (*(str
+ 1) != '\0' && *(str
+ 1) != '/')
1029 if (*(str
+ 1) == '/')
1030 state
= STATE_SLASH
;
1039 if (*(str
+ 1) == ':' || *(str
+ 1) == '.'
1040 || *(str
+ 1) == '\0' || *(str
+ 1) == '/')
1045 for (; sp
<= str
; sp
++)
1051 if (*(str
+ 1) == ':')
1052 state
= STATE_COLON
;
1053 else if (*(str
+ 1) == '.')
1055 if (colons
|| double_colon
)
1060 else if (*(str
+ 1) == '/')
1061 state
= STATE_SLASH
;
1068 if (*(str
+ 1) == '\0')
1069 return partly_match
;
1086 if (state
< STATE_MASK
)
1087 return partly_match
;
1089 mask
= strtol (str
, &endptr
, 10);
1090 if (*endptr
!= '\0')
1093 if (mask
< 0 || mask
> 128)
1096 /* I don't know why mask < 13 makes command match partly.
1097 Forgive me to make this comments. I Want to set static default route
1098 because of lack of function to originate default in ospf6d; sorry
1101 return partly_match;
1107 #endif /* HAVE_IPV6 */
1109 #define DECIMAL_STRLEN_MAX 20
1112 cmd_range_match (const char *range
, const char *str
)
1115 char buf
[DECIMAL_STRLEN_MAX
+ 1];
1116 char *endptr
= NULL
;
1117 signed long long min
, max
, val
;
1122 val
= strtoll (str
, &endptr
, 10);
1123 if (*endptr
!= '\0')
1128 p
= strchr (range
, '-');
1131 if (p
- range
> DECIMAL_STRLEN_MAX
)
1133 strncpy (buf
, range
, p
- range
);
1134 buf
[p
- range
] = '\0';
1135 min
= strtoll (buf
, &endptr
, 10);
1136 if (*endptr
!= '\0')
1140 p
= strchr (range
, '>');
1143 if (p
- range
> DECIMAL_STRLEN_MAX
)
1145 strncpy (buf
, range
, p
- range
);
1146 buf
[p
- range
] = '\0';
1147 max
= strtoll (buf
, &endptr
, 10);
1148 if (*endptr
!= '\0')
1151 if (val
< min
|| val
> max
)
1157 static enum match_type
1158 cmd_word_match(struct cmd_token
*token
,
1159 enum filter_type filter
,
1163 enum match_type match_type
;
1167 if (filter
== FILTER_RELAXED
)
1168 if (!word
|| !strlen(word
))
1169 return partly_match
;
1174 if (CMD_VARARG(str
))
1176 return vararg_match
;
1178 else if (CMD_RANGE(str
))
1180 if (cmd_range_match(str
, word
))
1184 else if (CMD_IPV6(str
))
1186 match_type
= cmd_ipv6_match(word
);
1187 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1188 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1191 else if (CMD_IPV6_PREFIX(str
))
1193 match_type
= cmd_ipv6_prefix_match(word
);
1194 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1195 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1196 return ipv6_prefix_match
;
1198 #endif /* HAVE_IPV6 */
1199 else if (CMD_IPV4(str
))
1201 match_type
= cmd_ipv4_match(word
);
1202 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1203 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1206 else if (CMD_IPV4_PREFIX(str
))
1208 match_type
= cmd_ipv4_prefix_match(word
);
1209 if ((filter
== FILTER_RELAXED
&& match_type
!= no_match
)
1210 || (filter
== FILTER_STRICT
&& match_type
== exact_match
))
1211 return ipv4_prefix_match
;
1213 else if (CMD_OPTION(str
) || CMD_VARIABLE(str
))
1215 return extend_match
;
1219 if (filter
== FILTER_RELAXED
&& !strncmp(str
, word
, strlen(word
)))
1221 if (!strcmp(str
, word
))
1223 return partly_match
;
1225 if (filter
== FILTER_STRICT
&& !strcmp(str
, word
))
1234 struct cmd_element
*cmd
; /* The command element the matcher is using */
1235 enum filter_type filter
; /* Whether to use strict or relaxed matching */
1236 vector vline
; /* The tokenized commandline which is to be matched */
1237 unsigned int index
; /* The index up to which matching should be done */
1239 /* If set, construct a list of matches at the position given by index */
1240 enum match_type
*match_type
;
1243 unsigned int word_index
; /* iterating over vline */
1247 push_argument(int *argc
, const char **argv
, const char *arg
)
1249 if (!arg
|| !strlen(arg
))
1255 if (*argc
>= CMD_ARGC_MAX
)
1258 argv
[(*argc
)++] = arg
;
1263 cmd_matcher_record_match(struct cmd_matcher
*matcher
,
1264 enum match_type match_type
,
1265 struct cmd_token
*token
)
1267 if (matcher
->word_index
!= matcher
->index
)
1272 if (!*matcher
->match
)
1273 *matcher
->match
= vector_init(VECTOR_MIN_SIZE
);
1274 vector_set(*matcher
->match
, token
);
1277 if (matcher
->match_type
)
1279 if (match_type
> *matcher
->match_type
)
1280 *matcher
->match_type
= match_type
;
1285 cmd_matcher_words_left(struct cmd_matcher
*matcher
)
1287 return matcher
->word_index
< vector_active(matcher
->vline
);
1291 cmd_matcher_get_word(struct cmd_matcher
*matcher
)
1293 assert(cmd_matcher_words_left(matcher
));
1295 return vector_slot(matcher
->vline
, matcher
->word_index
);
1298 static enum matcher_rv
1299 cmd_matcher_match_terminal(struct cmd_matcher
*matcher
,
1300 struct cmd_token
*token
,
1301 int *argc
, const char **argv
)
1304 enum match_type word_match
;
1306 assert(token
->type
== TOKEN_TERMINAL
);
1308 if (!cmd_matcher_words_left(matcher
))
1310 if (CMD_OPTION(token
->cmd
))
1311 return MATCHER_OK
; /* missing optional args are NOT pushed as NULL */
1313 return MATCHER_INCOMPLETE
;
1316 word
= cmd_matcher_get_word(matcher
);
1317 word_match
= cmd_word_match(token
, matcher
->filter
, word
);
1318 if (word_match
== no_match
)
1319 return MATCHER_NO_MATCH
;
1321 /* We have to record the input word as argument if it matched
1322 * against a variable. */
1323 if (CMD_VARARG(token
->cmd
)
1324 || CMD_VARIABLE(token
->cmd
)
1325 || CMD_OPTION(token
->cmd
))
1327 if (push_argument(argc
, argv
, word
))
1328 return MATCHER_EXCEED_ARGC_MAX
;
1331 cmd_matcher_record_match(matcher
, word_match
, token
);
1333 matcher
->word_index
++;
1335 /* A vararg token should consume all left over words as arguments */
1336 if (CMD_VARARG(token
->cmd
))
1337 while (cmd_matcher_words_left(matcher
))
1339 word
= cmd_matcher_get_word(matcher
);
1340 if (word
&& strlen(word
))
1341 push_argument(argc
, argv
, word
);
1342 matcher
->word_index
++;
1348 static enum matcher_rv
1349 cmd_matcher_match_multiple(struct cmd_matcher
*matcher
,
1350 struct cmd_token
*token
,
1351 int *argc
, const char **argv
)
1353 enum match_type multiple_match
;
1354 unsigned int multiple_index
;
1357 struct cmd_token
*word_token
;
1358 enum match_type word_match
;
1360 assert(token
->type
== TOKEN_MULTIPLE
);
1362 multiple_match
= no_match
;
1364 if (!cmd_matcher_words_left(matcher
))
1365 return MATCHER_INCOMPLETE
;
1367 word
= cmd_matcher_get_word(matcher
);
1368 for (multiple_index
= 0;
1369 multiple_index
< vector_active(token
->multiple
);
1372 word_token
= vector_slot(token
->multiple
, multiple_index
);
1374 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1375 if (word_match
== no_match
)
1378 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1380 if (word_match
> multiple_match
)
1382 multiple_match
= word_match
;
1385 /* To mimic the behavior of the old command implementation, we
1386 * tolerate any ambiguities here :/ */
1389 matcher
->word_index
++;
1391 if (multiple_match
== no_match
)
1392 return MATCHER_NO_MATCH
;
1394 if (push_argument(argc
, argv
, arg
))
1395 return MATCHER_EXCEED_ARGC_MAX
;
1400 static enum matcher_rv
1401 cmd_matcher_read_keywords(struct cmd_matcher
*matcher
,
1402 struct cmd_token
*token
,
1406 unsigned long keyword_mask
;
1407 unsigned int keyword_found
;
1408 enum match_type keyword_match
;
1409 enum match_type word_match
;
1410 vector keyword_vector
;
1411 struct cmd_token
*word_token
;
1414 const char **keyword_argv
;
1415 enum matcher_rv rv
= MATCHER_OK
;
1420 if (!cmd_matcher_words_left(matcher
))
1423 word
= cmd_matcher_get_word(matcher
);
1426 keyword_match
= no_match
;
1427 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1429 if (keyword_mask
& (1 << i
))
1432 keyword_vector
= vector_slot(token
->keyword
, i
);
1433 word_token
= vector_slot(keyword_vector
, 0);
1435 word_match
= cmd_word_match(word_token
, matcher
->filter
, word
);
1436 if (word_match
== no_match
)
1439 cmd_matcher_record_match(matcher
, word_match
, word_token
);
1441 if (word_match
> keyword_match
)
1443 keyword_match
= word_match
;
1446 else if (word_match
== keyword_match
)
1448 if (matcher
->word_index
!= matcher
->index
|| args_vector
)
1449 return MATCHER_AMBIGUOUS
;
1453 if (keyword_found
== (unsigned int)-1)
1454 return MATCHER_NO_MATCH
;
1456 matcher
->word_index
++;
1458 if (matcher
->word_index
> matcher
->index
)
1461 keyword_mask
|= (1 << keyword_found
);
1466 keyword_argv
= XMALLOC(MTYPE_TMP
, (CMD_ARGC_MAX
+ 1) * sizeof(char*));
1467 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1468 for (i
= 0; i
< CMD_ARGC_MAX
+ 1; i
++)
1469 keyword_argv
[i
] = (void*)-1;
1470 vector_set_index(args_vector
, keyword_found
, keyword_argv
);
1474 keyword_argv
= NULL
;
1477 keyword_vector
= vector_slot(token
->keyword
, keyword_found
);
1478 /* the keyword itself is at 0. We are only interested in the arguments,
1479 * so start counting at 1. */
1480 for (i
= 1; i
< vector_active(keyword_vector
); i
++)
1482 word_token
= vector_slot(keyword_vector
, i
);
1484 switch (word_token
->type
)
1486 case TOKEN_TERMINAL
:
1487 rv
= cmd_matcher_match_terminal(matcher
, word_token
,
1488 &keyword_argc
, keyword_argv
);
1490 case TOKEN_MULTIPLE
:
1491 rv
= cmd_matcher_match_multiple(matcher
, word_token
,
1492 &keyword_argc
, keyword_argv
);
1495 assert(!"Keywords should never be nested.");
1499 if (MATCHER_ERROR(rv
))
1502 if (matcher
->word_index
> matcher
->index
)
1509 static enum matcher_rv
1510 cmd_matcher_build_keyword_args(struct cmd_matcher
*matcher
,
1511 struct cmd_token
*token
,
1512 int *argc
, const char **argv
,
1513 vector keyword_args_vector
)
1516 const char **keyword_args
;
1517 vector keyword_vector
;
1518 struct cmd_token
*word_token
;
1524 if (keyword_args_vector
== NULL
)
1527 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
1529 keyword_vector
= vector_slot(token
->keyword
, i
);
1530 keyword_args
= vector_lookup(keyword_args_vector
, i
);
1532 if (vector_active(keyword_vector
) == 1)
1534 /* this is a keyword without arguments */
1537 word_token
= vector_slot(keyword_vector
, 0);
1538 arg
= word_token
->cmd
;
1545 if (push_argument(argc
, argv
, arg
))
1546 rv
= MATCHER_EXCEED_ARGC_MAX
;
1550 /* this is a keyword with arguments */
1553 /* the keyword was present, so just fill in the arguments */
1554 for (j
= 0; keyword_args
[j
] != (void*)-1; j
++)
1555 if (push_argument(argc
, argv
, keyword_args
[j
]))
1556 rv
= MATCHER_EXCEED_ARGC_MAX
;
1557 XFREE(MTYPE_TMP
, keyword_args
);
1561 /* the keyword was not present, insert NULL for the arguments
1562 * the keyword would have taken. */
1563 for (j
= 1; j
< vector_active(keyword_vector
); j
++)
1565 word_token
= vector_slot(keyword_vector
, j
);
1566 if ((word_token
->type
== TOKEN_TERMINAL
1567 && (CMD_VARARG(word_token
->cmd
)
1568 || CMD_VARIABLE(word_token
->cmd
)
1569 || CMD_OPTION(word_token
->cmd
)))
1570 || word_token
->type
== TOKEN_MULTIPLE
)
1572 if (push_argument(argc
, argv
, NULL
))
1573 rv
= MATCHER_EXCEED_ARGC_MAX
;
1579 vector_free(keyword_args_vector
);
1583 static enum matcher_rv
1584 cmd_matcher_match_keyword(struct cmd_matcher
*matcher
,
1585 struct cmd_token
*token
,
1586 int *argc
, const char **argv
)
1588 vector keyword_args_vector
;
1589 enum matcher_rv reader_rv
;
1590 enum matcher_rv builder_rv
;
1592 assert(token
->type
== TOKEN_KEYWORD
);
1595 keyword_args_vector
= vector_init(VECTOR_MIN_SIZE
);
1597 keyword_args_vector
= NULL
;
1599 reader_rv
= cmd_matcher_read_keywords(matcher
, token
, keyword_args_vector
);
1600 builder_rv
= cmd_matcher_build_keyword_args(matcher
, token
, argc
,
1601 argv
, keyword_args_vector
);
1602 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1604 if (!MATCHER_ERROR(reader_rv
) && MATCHER_ERROR(builder_rv
))
1611 cmd_matcher_init(struct cmd_matcher
*matcher
,
1612 struct cmd_element
*cmd
,
1613 enum filter_type filter
,
1616 enum match_type
*match_type
,
1619 memset(matcher
, 0, sizeof(*matcher
));
1622 matcher
->filter
= filter
;
1623 matcher
->vline
= vline
;
1624 matcher
->index
= index
;
1626 matcher
->match_type
= match_type
;
1627 if (matcher
->match_type
)
1628 *matcher
->match_type
= no_match
;
1629 matcher
->match
= match
;
1631 matcher
->word_index
= 0;
1634 static enum matcher_rv
1635 cmd_element_match(struct cmd_element
*cmd_element
,
1636 enum filter_type filter
,
1639 enum match_type
*match_type
,
1644 struct cmd_matcher matcher
;
1645 unsigned int token_index
;
1646 enum matcher_rv rv
= MATCHER_OK
;
1648 cmd_matcher_init(&matcher
, cmd_element
, filter
,
1649 vline
, index
, match_type
, match
);
1654 for (token_index
= 0;
1655 token_index
< vector_active(cmd_element
->tokens
);
1658 struct cmd_token
*token
= vector_slot(cmd_element
->tokens
, token_index
);
1660 switch (token
->type
)
1662 case TOKEN_TERMINAL
:
1663 rv
= cmd_matcher_match_terminal(&matcher
, token
, argc
, argv
);
1665 case TOKEN_MULTIPLE
:
1666 rv
= cmd_matcher_match_multiple(&matcher
, token
, argc
, argv
);
1669 rv
= cmd_matcher_match_keyword(&matcher
, token
, argc
, argv
);
1672 if (MATCHER_ERROR(rv
))
1675 if (matcher
.word_index
> index
)
1679 /* return MATCHER_COMPLETE if all words were consumed */
1680 if (matcher
.word_index
>= vector_active(vline
))
1681 return MATCHER_COMPLETE
;
1683 /* return MATCHER_COMPLETE also if only an empty word is left. */
1684 if (matcher
.word_index
== vector_active(vline
) - 1
1685 && (!vector_slot(vline
, matcher
.word_index
)
1686 || !strlen((char*)vector_slot(vline
, matcher
.word_index
))))
1687 return MATCHER_COMPLETE
;
1689 return MATCHER_NO_MATCH
; /* command is too long to match */
1693 * Filter a given vector of commands against a given commandline and
1694 * calculate possible completions.
1696 * @param commands A vector of struct cmd_element*. Commands that don't
1697 * match against the given command line will be overwritten
1698 * with NULL in that vector.
1699 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1700 * determines how incomplete commands are handled, compare with
1701 * cmd_word_match for details.
1702 * @param vline A vector of char* containing the tokenized commandline.
1703 * @param index Only match up to the given token of the commandline.
1704 * @param match_type Record the type of the best match here.
1705 * @param matches Record the matches here. For each cmd_element in the commands
1706 * vector, a match vector will be created in the matches vector.
1707 * That vector will contain all struct command_token* of the
1708 * cmd_element which matched against the given vline at the given
1710 * @return A code specifying if an error occured. If all went right, it's
1714 cmd_vector_filter(vector commands
,
1715 enum filter_type filter
,
1718 enum match_type
*match_type
,
1722 struct cmd_element
*cmd_element
;
1723 enum match_type best_match
;
1724 enum match_type element_match
;
1725 enum matcher_rv matcher_rv
;
1727 best_match
= no_match
;
1728 *matches
= vector_init(VECTOR_MIN_SIZE
);
1730 for (i
= 0; i
< vector_active (commands
); i
++)
1731 if ((cmd_element
= vector_slot (commands
, i
)) != NULL
)
1733 vector_set_index(*matches
, i
, NULL
);
1734 matcher_rv
= cmd_element_match(cmd_element
, filter
,
1737 (vector
*)&vector_slot(*matches
, i
),
1739 if (MATCHER_ERROR(matcher_rv
))
1741 vector_slot(commands
, i
) = NULL
;
1742 if (matcher_rv
== MATCHER_AMBIGUOUS
)
1743 return CMD_ERR_AMBIGUOUS
;
1744 if (matcher_rv
== MATCHER_EXCEED_ARGC_MAX
)
1745 return CMD_ERR_EXEED_ARGC_MAX
;
1747 else if (element_match
> best_match
)
1749 best_match
= element_match
;
1752 *match_type
= best_match
;
1757 * Check whether a given commandline is complete if used for a specific
1760 * @param cmd_element A cmd_element against which the commandline should be
1762 * @param vline The tokenized commandline.
1763 * @return 1 if the given commandline is complete, 0 otherwise.
1766 cmd_is_complete(struct cmd_element
*cmd_element
,
1771 rv
= cmd_element_match(cmd_element
,
1776 return (rv
== MATCHER_COMPLETE
);
1780 * Parse a given commandline and construct a list of arguments for the
1781 * given command_element.
1783 * @param cmd_element The cmd_element for which we want to construct arguments.
1784 * @param vline The tokenized commandline.
1785 * @param argc Where to store the argument count.
1786 * @param argv Where to store the argument list. Should be at least
1787 * CMD_ARGC_MAX elements long.
1788 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1791 cmd_parse(struct cmd_element
*cmd_element
,
1793 int *argc
, const char **argv
)
1795 enum matcher_rv rv
= cmd_element_match(cmd_element
,
1802 case MATCHER_COMPLETE
:
1805 case MATCHER_NO_MATCH
:
1806 return CMD_ERR_NO_MATCH
;
1808 case MATCHER_AMBIGUOUS
:
1809 return CMD_ERR_AMBIGUOUS
;
1811 case MATCHER_EXCEED_ARGC_MAX
:
1812 return CMD_ERR_EXEED_ARGC_MAX
;
1815 return CMD_ERR_INCOMPLETE
;
1819 /* Check ambiguous match */
1821 is_cmd_ambiguous (vector cmd_vector
,
1822 const char *command
,
1824 enum match_type type
)
1828 const char *str
= NULL
;
1829 const char *matched
= NULL
;
1830 vector match_vector
;
1831 struct cmd_token
*cmd_token
;
1833 if (command
== NULL
)
1836 for (i
= 0; i
< vector_active (matches
); i
++)
1837 if ((match_vector
= vector_slot (matches
, i
)) != NULL
)
1841 for (j
= 0; j
< vector_active (match_vector
); j
++)
1842 if ((cmd_token
= vector_slot (match_vector
, j
)) != NULL
)
1844 enum match_type ret
;
1846 assert(cmd_token
->type
== TOKEN_TERMINAL
);
1847 if (cmd_token
->type
!= TOKEN_TERMINAL
)
1850 str
= cmd_token
->cmd
;
1855 if (!(CMD_OPTION (str
) || CMD_VARIABLE (str
))
1856 && strcmp (command
, str
) == 0)
1860 if (!(CMD_OPTION (str
) || CMD_VARIABLE (str
))
1861 && strncmp (command
, str
, strlen (command
)) == 0)
1863 if (matched
&& strcmp (matched
, str
) != 0)
1864 return 1; /* There is ambiguous match. */
1871 if (cmd_range_match (str
, command
))
1873 if (matched
&& strcmp (matched
, str
) != 0)
1885 case ipv6_prefix_match
:
1886 if ((ret
= cmd_ipv6_prefix_match (command
)) != no_match
)
1888 if (ret
== partly_match
)
1889 return 2; /* There is incomplete match. */
1894 #endif /* HAVE_IPV6 */
1899 case ipv4_prefix_match
:
1900 if ((ret
= cmd_ipv4_prefix_match (command
)) != no_match
)
1902 if (ret
== partly_match
)
1903 return 2; /* There is incomplete match. */
1909 if (CMD_OPTION (str
) || CMD_VARIABLE (str
))
1918 vector_slot (cmd_vector
, i
) = NULL
;
1923 /* If src matches dst return dst string, otherwise return NULL */
1925 cmd_entry_function (const char *src
, const char *dst
)
1927 /* Skip variable arguments. */
1928 if (CMD_OPTION (dst
) || CMD_VARIABLE (dst
) || CMD_VARARG (dst
) ||
1929 CMD_IPV4 (dst
) || CMD_IPV4_PREFIX (dst
) || CMD_RANGE (dst
))
1932 /* In case of 'command \t', given src is NULL string. */
1936 /* Matched with input string. */
1937 if (strncmp (src
, dst
, strlen (src
)) == 0)
1943 /* If src matches dst return dst string, otherwise return NULL */
1944 /* This version will return the dst string always if it is
1945 CMD_VARIABLE for '?' key processing */
1947 cmd_entry_function_desc (const char *src
, const char *dst
)
1949 if (CMD_VARARG (dst
))
1952 if (CMD_RANGE (dst
))
1954 if (cmd_range_match (dst
, src
))
1963 if (cmd_ipv6_match (src
))
1969 if (CMD_IPV6_PREFIX (dst
))
1971 if (cmd_ipv6_prefix_match (src
))
1976 #endif /* HAVE_IPV6 */
1980 if (cmd_ipv4_match (src
))
1986 if (CMD_IPV4_PREFIX (dst
))
1988 if (cmd_ipv4_prefix_match (src
))
1994 /* Optional or variable commands always match on '?' */
1995 if (CMD_OPTION (dst
) || CMD_VARIABLE (dst
))
1998 /* In case of 'command \t', given src is NULL string. */
2002 if (strncmp (src
, dst
, strlen (src
)) == 0)
2009 * Check whether a string is already present in a vector of strings.
2010 * @param v A vector of char*.
2011 * @param str A char*.
2012 * @return 0 if str is already present in the vector, 1 otherwise.
2015 cmd_unique_string (vector v
, const char *str
)
2020 for (i
= 0; i
< vector_active (v
); i
++)
2021 if ((match
= vector_slot (v
, i
)) != NULL
)
2022 if (strcmp (match
, str
) == 0)
2028 * Check whether a struct cmd_token matching a given string is already
2029 * present in a vector of struct cmd_token.
2030 * @param v A vector of struct cmd_token*.
2031 * @param str A char* which should be searched for.
2032 * @return 0 if there is a struct cmd_token* with its cmd matching str,
2036 desc_unique_string (vector v
, const char *str
)
2039 struct cmd_token
*token
;
2041 for (i
= 0; i
< vector_active (v
); i
++)
2042 if ((token
= vector_slot (v
, i
)) != NULL
)
2043 if (strcmp (token
->cmd
, str
) == 0)
2049 cmd_try_do_shortcut (enum node_type node
, char* first_word
) {
2050 if ( first_word
!= NULL
&&
2051 node
!= AUTH_NODE
&&
2052 node
!= VIEW_NODE
&&
2053 node
!= AUTH_ENABLE_NODE
&&
2054 node
!= ENABLE_NODE
&&
2055 node
!= RESTRICTED_NODE
&&
2056 0 == strcmp( "do", first_word
) )
2062 cmd_matches_free(vector
*matches
)
2067 for (i
= 0; i
< vector_active(*matches
); i
++)
2068 if ((cmd_matches
= vector_slot(*matches
, i
)) != NULL
)
2069 vector_free(cmd_matches
);
2070 vector_free(*matches
);
2075 cmd_describe_cmp(const void *a
, const void *b
)
2077 const struct cmd_token
*first
= *(struct cmd_token
* const *)a
;
2078 const struct cmd_token
*second
= *(struct cmd_token
* const *)b
;
2080 return strcmp(first
->cmd
, second
->cmd
);
2084 cmd_describe_sort(vector matchvec
)
2086 qsort(matchvec
->index
, vector_active(matchvec
),
2087 sizeof(void*), cmd_describe_cmp
);
2090 /* '?' describe command support. */
2092 cmd_describe_command_real (vector vline
, struct vty
*vty
, int *status
)
2096 #define INIT_MATCHVEC_SIZE 10
2098 struct cmd_element
*cmd_element
;
2101 enum match_type match
;
2103 vector matches
= NULL
;
2104 vector match_vector
;
2105 uint32_t command_found
= 0;
2106 const char *last_word
;
2109 if (vector_active (vline
) == 0)
2111 *status
= CMD_ERR_NO_MATCH
;
2115 index
= vector_active (vline
) - 1;
2117 /* Make copy vector of current node's command vector. */
2118 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2120 /* Prepare match vector */
2121 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2123 /* Filter commands and build a list how they could possibly continue. */
2124 for (i
= 0; i
<= index
; i
++)
2126 command
= vector_slot (vline
, i
);
2129 cmd_matches_free(&matches
);
2131 ret
= cmd_vector_filter(cmd_vector
,
2137 if (ret
!= CMD_SUCCESS
)
2139 vector_free (cmd_vector
);
2140 vector_free (matchvec
);
2141 cmd_matches_free(&matches
);
2146 /* The last match may well be ambigious, so break here */
2150 if (match
== vararg_match
)
2152 /* We found a vararg match - so we can throw out the current matches here
2153 * and don't need to continue checking the command input */
2156 for (j
= 0; j
< vector_active (matches
); j
++)
2157 if ((match_vector
= vector_slot (matches
, j
)) != NULL
)
2158 for (k
= 0; k
< vector_active (match_vector
); k
++)
2160 struct cmd_token
*token
= vector_slot (match_vector
, k
);
2161 vector_set (matchvec
, token
);
2164 *status
= CMD_SUCCESS
;
2165 vector_set(matchvec
, &token_cr
);
2166 vector_free (cmd_vector
);
2167 cmd_matches_free(&matches
);
2168 cmd_describe_sort(matchvec
);
2172 ret
= is_cmd_ambiguous(cmd_vector
, command
, matches
, match
);
2175 vector_free (cmd_vector
);
2176 vector_free (matchvec
);
2177 cmd_matches_free(&matches
);
2178 *status
= CMD_ERR_AMBIGUOUS
;
2183 vector_free (cmd_vector
);
2184 vector_free (matchvec
);
2185 cmd_matches_free(&matches
);
2186 *status
= CMD_ERR_NO_MATCH
;
2191 /* Make description vector. */
2192 for (i
= 0; i
< vector_active (matches
); i
++) {
2193 if ((cmd_element
= vector_slot (cmd_vector
, i
)) != NULL
)
2196 vector vline_trimmed
;
2199 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2200 if (last_word
== NULL
|| !strlen(last_word
))
2202 vline_trimmed
= vector_copy(vline
);
2203 vector_unset(vline_trimmed
, vector_active(vline_trimmed
) - 1);
2205 if (cmd_is_complete(cmd_element
, vline_trimmed
)
2206 && desc_unique_string(matchvec
, command_cr
))
2208 if (match
!= vararg_match
)
2209 vector_set(matchvec
, &token_cr
);
2212 vector_free(vline_trimmed
);
2215 match_vector
= vector_slot (matches
, i
);
2217 for (j
= 0; j
< vector_active(match_vector
); j
++)
2219 struct cmd_token
*token
= vector_slot(match_vector
, j
);
2222 string
= cmd_entry_function_desc(command
, token
->cmd
);
2223 if (string
&& desc_unique_string(matchvec
, string
))
2224 vector_set(matchvec
, token
);
2230 * We can get into this situation when the command is complete
2231 * but the last part of the command is an optional piece of
2234 last_word
= vector_slot(vline
, vector_active(vline
) - 1);
2235 if (command_found
== 0 && (last_word
== NULL
|| !strlen(last_word
))) {
2236 vector_set(matchvec
, &token_cr
);
2239 vector_free (cmd_vector
);
2240 cmd_matches_free(&matches
);
2242 if (vector_slot (matchvec
, 0) == NULL
)
2244 vector_free (matchvec
);
2245 *status
= CMD_ERR_NO_MATCH
;
2249 *status
= CMD_SUCCESS
;
2250 cmd_describe_sort(matchvec
);
2255 cmd_describe_command (vector vline
, struct vty
*vty
, int *status
)
2259 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2261 enum node_type onode
;
2262 vector shifted_vline
;
2266 vty
->node
= ENABLE_NODE
;
2267 /* We can try it on enable node, cos' the vty is authenticated */
2269 shifted_vline
= vector_init (vector_count(vline
));
2271 for (index
= 1; index
< vector_active (vline
); index
++)
2273 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2276 ret
= cmd_describe_command_real (shifted_vline
, vty
, status
);
2278 vector_free(shifted_vline
);
2284 return cmd_describe_command_real (vline
, vty
, status
);
2288 /* Check LCD of matched command. */
2290 cmd_lcd (char **matched
)
2298 if (matched
[0] == NULL
|| matched
[1] == NULL
)
2301 for (i
= 1; matched
[i
] != NULL
; i
++)
2303 s1
= matched
[i
- 1];
2306 for (j
= 0; (c1
= s1
[j
]) && (c2
= s2
[j
]); j
++)
2322 cmd_complete_cmp(const void *a
, const void *b
)
2324 const char *first
= *(char * const *)a
;
2325 const char *second
= *(char * const *)b
;
2336 return strcmp(first
, second
);
2340 cmd_complete_sort(vector matchvec
)
2342 qsort(matchvec
->index
, vector_active(matchvec
),
2343 sizeof(void*), cmd_complete_cmp
);
2346 /* Command line completion support. */
2348 cmd_complete_command_real (vector vline
, struct vty
*vty
, int *status
)
2351 vector cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2352 #define INIT_MATCHVEC_SIZE 10
2356 struct cmd_token
*token
;
2359 vector matches
= NULL
;
2360 vector match_vector
;
2362 if (vector_active (vline
) == 0)
2364 vector_free (cmd_vector
);
2365 *status
= CMD_ERR_NO_MATCH
;
2369 index
= vector_active (vline
) - 1;
2371 /* First, filter by command string */
2372 for (i
= 0; i
<= index
; i
++)
2374 command
= vector_slot (vline
, i
);
2375 enum match_type match
;
2379 cmd_matches_free(&matches
);
2381 /* First try completion match, if there is exactly match return 1 */
2382 ret
= cmd_vector_filter(cmd_vector
,
2388 if (ret
!= CMD_SUCCESS
)
2390 vector_free(cmd_vector
);
2391 cmd_matches_free(&matches
);
2396 /* Break here - the completion mustn't be checked to be non-ambiguous */
2400 /* If there is exact match then filter ambiguous match else check
2402 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2405 vector_free (cmd_vector
);
2406 cmd_matches_free(&matches
);
2407 *status
= CMD_ERR_AMBIGUOUS
;
2413 vector_free (cmd_vector);
2414 cmd_matches_free(&matches);
2415 *status = CMD_ERR_NO_MATCH;
2421 /* Prepare match vector. */
2422 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2424 /* Build the possible list of continuations into a list of completions */
2425 for (i
= 0; i
< vector_active (matches
); i
++)
2426 if ((match_vector
= vector_slot (matches
, i
)))
2431 for (j
= 0; j
< vector_active (match_vector
); j
++)
2432 if ((token
= vector_slot (match_vector
, j
)))
2435 cmd_entry_function (vector_slot (vline
, index
),
2437 if (cmd_unique_string (matchvec
, string
))
2438 vector_set (matchvec
, XSTRDUP (MTYPE_TMP
, string
));
2442 /* We don't need cmd_vector any more. */
2443 vector_free (cmd_vector
);
2444 cmd_matches_free(&matches
);
2446 /* No matched command */
2447 if (vector_slot (matchvec
, 0) == NULL
)
2449 vector_free (matchvec
);
2451 /* In case of 'command \t' pattern. Do you need '?' command at
2452 the end of the line. */
2453 if (vector_slot (vline
, index
) == '\0')
2454 *status
= CMD_ERR_NOTHING_TODO
;
2456 *status
= CMD_ERR_NO_MATCH
;
2460 /* Only one matched */
2461 if (vector_slot (matchvec
, 1) == NULL
)
2463 match_str
= (char **) matchvec
->index
;
2464 vector_only_wrapper_free (matchvec
);
2465 *status
= CMD_COMPLETE_FULL_MATCH
;
2468 /* Make it sure last element is NULL. */
2469 vector_set (matchvec
, NULL
);
2471 /* Check LCD of matched strings. */
2472 if (vector_slot (vline
, index
) != NULL
)
2474 lcd
= cmd_lcd ((char **) matchvec
->index
);
2478 int len
= strlen (vector_slot (vline
, index
));
2484 lcdstr
= XMALLOC (MTYPE_TMP
, lcd
+ 1);
2485 memcpy (lcdstr
, matchvec
->index
[0], lcd
);
2488 /* match_str = (char **) &lcdstr; */
2490 /* Free matchvec. */
2491 for (i
= 0; i
< vector_active (matchvec
); i
++)
2493 if (vector_slot (matchvec
, i
))
2494 XFREE (MTYPE_TMP
, vector_slot (matchvec
, i
));
2496 vector_free (matchvec
);
2498 /* Make new matchvec. */
2499 matchvec
= vector_init (INIT_MATCHVEC_SIZE
);
2500 vector_set (matchvec
, lcdstr
);
2501 match_str
= (char **) matchvec
->index
;
2502 vector_only_wrapper_free (matchvec
);
2504 *status
= CMD_COMPLETE_MATCH
;
2510 match_str
= (char **) matchvec
->index
;
2511 cmd_complete_sort(matchvec
);
2512 vector_only_wrapper_free (matchvec
);
2513 *status
= CMD_COMPLETE_LIST_MATCH
;
2518 cmd_complete_command (vector vline
, struct vty
*vty
, int *status
)
2522 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2524 enum node_type onode
;
2525 vector shifted_vline
;
2529 vty
->node
= ENABLE_NODE
;
2530 /* We can try it on enable node, cos' the vty is authenticated */
2532 shifted_vline
= vector_init (vector_count(vline
));
2534 for (index
= 1; index
< vector_active (vline
); index
++)
2536 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2539 ret
= cmd_complete_command_real (shifted_vline
, vty
, status
);
2541 vector_free(shifted_vline
);
2547 return cmd_complete_command_real (vline
, vty
, status
);
2550 /* return parent node */
2551 /* MUST eventually converge on CONFIG_NODE */
2553 node_parent ( enum node_type node
)
2557 assert (node
> CONFIG_NODE
);
2561 case BGP_VPNV4_NODE
:
2563 case BGP_IPV4M_NODE
:
2565 case BGP_IPV6M_NODE
:
2568 case KEYCHAIN_KEY_NODE
:
2569 ret
= KEYCHAIN_NODE
;
2578 /* Execute command by argument vline vector. */
2580 cmd_execute_command_real (vector vline
,
2581 enum filter_type filter
,
2583 struct cmd_element
**cmd
)
2588 struct cmd_element
*cmd_element
;
2589 struct cmd_element
*matched_element
;
2590 unsigned int matched_count
, incomplete_count
;
2592 const char *argv
[CMD_ARGC_MAX
];
2593 enum match_type match
= 0;
2598 /* Make copy of command elements. */
2599 cmd_vector
= vector_copy (cmd_node_vector (cmdvec
, vty
->node
));
2601 for (index
= 0; index
< vector_active (vline
); index
++)
2603 command
= vector_slot (vline
, index
);
2604 ret
= cmd_vector_filter(cmd_vector
,
2610 if (ret
!= CMD_SUCCESS
)
2612 cmd_matches_free(&matches
);
2616 if (match
== vararg_match
)
2618 cmd_matches_free(&matches
);
2622 ret
= is_cmd_ambiguous (cmd_vector
, command
, matches
, match
);
2623 cmd_matches_free(&matches
);
2627 vector_free(cmd_vector
);
2628 return CMD_ERR_AMBIGUOUS
;
2632 vector_free(cmd_vector
);
2633 return CMD_ERR_NO_MATCH
;
2637 /* Check matched count. */
2638 matched_element
= NULL
;
2640 incomplete_count
= 0;
2642 for (i
= 0; i
< vector_active (cmd_vector
); i
++)
2643 if ((cmd_element
= vector_slot (cmd_vector
, i
)))
2645 if (cmd_is_complete(cmd_element
, vline
))
2647 matched_element
= cmd_element
;
2656 /* Finish of using cmd_vector. */
2657 vector_free (cmd_vector
);
2659 /* To execute command, matched_count must be 1. */
2660 if (matched_count
== 0)
2662 if (incomplete_count
)
2663 return CMD_ERR_INCOMPLETE
;
2665 return CMD_ERR_NO_MATCH
;
2668 if (matched_count
> 1)
2669 return CMD_ERR_AMBIGUOUS
;
2671 ret
= cmd_parse(matched_element
, vline
, &argc
, argv
);
2672 if (ret
!= CMD_SUCCESS
)
2675 /* For vtysh execution. */
2677 *cmd
= matched_element
;
2679 if (matched_element
->daemon
)
2680 return CMD_SUCCESS_DAEMON
;
2682 /* Execute matched command. */
2683 return (*matched_element
->func
) (matched_element
, vty
, argc
, argv
);
2687 * Execute a given command, handling things like "do ..." and checking
2688 * whether the given command might apply at a parent node if doesn't
2689 * apply for the current node.
2691 * @param vline Command line input, vector of char* where each element is
2693 * @param vty The vty context in which the command should be executed.
2694 * @param cmd Pointer where the struct cmd_element of the matched command
2695 * will be stored, if any. May be set to NULL if this info is
2697 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2698 * @return The status of the command that has been executed or an error code
2699 * as to why no command could be executed.
2702 cmd_execute_command (vector vline
, struct vty
*vty
, struct cmd_element
**cmd
,
2704 int ret
, saved_ret
, tried
= 0;
2705 enum node_type onode
, try_node
;
2707 onode
= try_node
= vty
->node
;
2709 if ( cmd_try_do_shortcut(vty
->node
, vector_slot(vline
, 0) ) )
2711 vector shifted_vline
;
2714 vty
->node
= ENABLE_NODE
;
2715 /* We can try it on enable node, cos' the vty is authenticated */
2717 shifted_vline
= vector_init (vector_count(vline
));
2719 for (index
= 1; index
< vector_active (vline
); index
++)
2721 vector_set_index (shifted_vline
, index
-1, vector_lookup(vline
, index
));
2724 ret
= cmd_execute_command_real (shifted_vline
, FILTER_RELAXED
, vty
, cmd
);
2726 vector_free(shifted_vline
);
2732 saved_ret
= ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2737 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2738 while ( ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
2739 && vty
->node
> CONFIG_NODE
)
2741 try_node
= node_parent(try_node
);
2742 vty
->node
= try_node
;
2743 ret
= cmd_execute_command_real (vline
, FILTER_RELAXED
, vty
, cmd
);
2745 if (ret
== CMD_SUCCESS
|| ret
== CMD_WARNING
)
2747 /* succesfull command, leave the node as is */
2751 /* no command succeeded, reset the vty to the original node and
2752 return the error for this node */
2759 * Execute a given command, matching it strictly against the current node.
2760 * This mode is used when reading config files.
2762 * @param vline Command line input, vector of char* where each element is
2764 * @param vty The vty context in which the command should be executed.
2765 * @param cmd Pointer where the struct cmd_element* of the matched command
2766 * will be stored, if any. May be set to NULL if this info is
2768 * @return The status of the command that has been executed or an error code
2769 * as to why no command could be executed.
2772 cmd_execute_command_strict (vector vline
, struct vty
*vty
,
2773 struct cmd_element
**cmd
)
2775 return cmd_execute_command_real(vline
, FILTER_STRICT
, vty
, cmd
);
2779 * Parse one line of config, walking up the parse tree attempting to find a match
2781 * @param vty The vty context in which the command should be executed.
2782 * @param cmd Pointer where the struct cmd_element* of the match command
2783 * will be stored, if any. May be set to NULL if this info is
2785 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2787 * @return The status of the command that has been executed or an error code
2788 * as to why no command could be executed.
2791 command_config_read_one_line (struct vty
*vty
, struct cmd_element
**cmd
, int use_daemon
)
2797 vline
= cmd_make_strvec (vty
->buf
);
2799 /* In case of comment line */
2803 /* Execute configuration command : this is strict match */
2804 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2806 // Climb the tree and try the command again at each node
2807 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2808 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2809 ret
!= CMD_SUCCESS
&&
2810 ret
!= CMD_WARNING
&&
2811 vty
->node
!= CONFIG_NODE
) {
2813 saved_node
= vty
->node
;
2815 while (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2816 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2817 ret
!= CMD_SUCCESS
&&
2818 ret
!= CMD_WARNING
&&
2819 vty
->node
!= CONFIG_NODE
) {
2820 vty
->node
= node_parent(vty
->node
);
2821 ret
= cmd_execute_command_strict (vline
, vty
, cmd
);
2824 // If climbing the tree did not work then ignore the command and
2825 // stay at the same node
2826 if (!(use_daemon
&& ret
== CMD_SUCCESS_DAEMON
) &&
2827 !(!use_daemon
&& ret
== CMD_ERR_NOTHING_TODO
) &&
2828 ret
!= CMD_SUCCESS
&&
2831 vty
->node
= saved_node
;
2832 memcpy(vty
->error_buf
, vty
->buf
, VTY_BUFSIZ
);
2836 cmd_free_strvec (vline
);
2841 /* Configuration make from file. */
2843 config_from_file (struct vty
*vty
, FILE *fp
, unsigned int *line_num
)
2845 int ret
, error_ret
=0;
2848 while (fgets (vty
->buf
, VTY_BUFSIZ
, fp
))
2853 ret
= command_config_read_one_line (vty
, NULL
, 0);
2855 if (ret
!= CMD_SUCCESS
&& ret
!= CMD_WARNING
&&
2856 ret
!= CMD_ERR_NOTHING_TODO
)
2867 /* Configuration from terminal */
2868 DEFUN (config_terminal
,
2869 config_terminal_cmd
,
2870 "configure terminal",
2871 "Configuration from vty interface\n"
2872 "Configuration terminal\n")
2874 if (vty_config_lock (vty
))
2875 vty
->node
= CONFIG_NODE
;
2878 vty_out (vty
, "VTY configuration is locked by other VTY%s", VTY_NEWLINE
);
2884 /* Enable command */
2888 "Turn on privileged mode command\n")
2890 /* If enable password is NULL, change to ENABLE_NODE */
2891 if ((host
.enable
== NULL
&& host
.enable_encrypt
== NULL
) ||
2892 vty
->type
== VTY_SHELL_SERV
)
2893 vty
->node
= ENABLE_NODE
;
2895 vty
->node
= AUTH_ENABLE_NODE
;
2900 /* Disable command */
2904 "Turn off privileged mode command\n")
2906 if (vty
->node
== ENABLE_NODE
)
2907 vty
->node
= VIEW_NODE
;
2911 /* Down vty node level. */
2915 "Exit current mode and down to previous mode\n")
2921 case RESTRICTED_NODE
:
2922 if (vty_shell (vty
))
2925 vty
->status
= VTY_CLOSE
;
2928 vty
->node
= ENABLE_NODE
;
2929 vty_config_unlock (vty
);
2931 case INTERFACE_NODE
:
2944 vty
->node
= CONFIG_NODE
;
2946 case BGP_VPNV4_NODE
:
2948 case BGP_IPV4M_NODE
:
2950 case BGP_IPV6M_NODE
:
2951 vty
->node
= BGP_NODE
;
2953 case KEYCHAIN_KEY_NODE
:
2954 vty
->node
= KEYCHAIN_NODE
;
2962 /* quit is alias of exit. */
2966 "Exit current mode and down to previous mode\n")
2968 /* End of configuration. */
2972 "End current mode and change to enable mode.")
2978 case RESTRICTED_NODE
:
2979 /* Nothing to do. */
2982 case INTERFACE_NODE
:
2988 case BGP_VPNV4_NODE
:
2990 case BGP_IPV4M_NODE
:
2992 case BGP_IPV6M_NODE
:
2998 case KEYCHAIN_KEY_NODE
:
3001 vty_config_unlock (vty
);
3002 vty
->node
= ENABLE_NODE
;
3011 DEFUN (show_version
,
3015 "Displays zebra version\n")
3017 vty_out (vty
, "Quagga %s (%s).%s", QUAGGA_VERSION
, host
.name
?host
.name
:"",
3019 vty_out (vty
, "%s%s%s", QUAGGA_COPYRIGHT
, GIT_INFO
, VTY_NEWLINE
);
3024 /* Help display function for all node. */
3028 "Description of the interactive help system\n")
3031 "Quagga VTY provides advanced help feature. When you need help,%s\
3032 anytime at the command line please press '?'.%s\
3034 If nothing matches, the help list will be empty and you must backup%s\
3035 until entering a '?' shows the available options.%s\
3036 Two styles of help are provided:%s\
3037 1. Full help is available when you are ready to enter a%s\
3038 command argument (e.g. 'show ?') and describes each possible%s\
3040 2. Partial help is provided when an abbreviated argument is entered%s\
3041 and you want to know what arguments match the input%s\
3042 (e.g. 'show me?'.)%s%s", VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3043 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
,
3044 VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
, VTY_NEWLINE
);
3048 /* Help display function for all node. */
3052 "Print command list\n")
3055 struct cmd_node
*cnode
= vector_slot (cmdvec
, vty
->node
);
3056 struct cmd_element
*cmd
;
3058 for (i
= 0; i
< vector_active (cnode
->cmd_vector
); i
++)
3059 if ((cmd
= vector_slot (cnode
->cmd_vector
, i
)) != NULL
3060 && !(cmd
->attr
== CMD_ATTR_DEPRECATED
3061 || cmd
->attr
== CMD_ATTR_HIDDEN
))
3062 vty_out (vty
, " %s%s", cmd
->string
,
3067 /* Write current configuration into file. */
3068 DEFUN (config_write_file
,
3069 config_write_file_cmd
,
3071 "Write running configuration to memory, network, or terminal\n"
3072 "Write to configuration file\n")
3076 struct cmd_node
*node
;
3078 char *config_file_tmp
= NULL
;
3079 char *config_file_sav
= NULL
;
3080 int ret
= CMD_WARNING
;
3081 struct vty
*file_vty
;
3082 struct stat conf_stat
;
3084 /* Check and see if we are operating under vtysh configuration */
3085 if (host
.config
== NULL
)
3087 vty_out (vty
, "Can't save to configuration file, using vtysh.%s",
3093 config_file
= host
.config
;
3096 XMALLOC (MTYPE_TMP
, strlen (config_file
) + strlen (CONF_BACKUP_EXT
) + 1);
3097 strcpy (config_file_sav
, config_file
);
3098 strcat (config_file_sav
, CONF_BACKUP_EXT
);
3101 config_file_tmp
= XMALLOC (MTYPE_TMP
, strlen (config_file
) + 8);
3102 sprintf (config_file_tmp
, "%s.XXXXXX", config_file
);
3104 /* Open file to configuration write. */
3105 fd
= mkstemp (config_file_tmp
);
3108 vty_out (vty
, "Can't open configuration file %s.%s", config_file_tmp
,
3113 /* Make vty for configuration file. */
3114 file_vty
= vty_new ();
3116 file_vty
->type
= VTY_FILE
;
3118 /* Config file header print. */
3119 vty_out (file_vty
, "!\n! Zebra configuration saved from vty\n! ");
3120 vty_time_print (file_vty
, 1);
3121 vty_out (file_vty
, "!\n");
3123 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3124 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3126 if ((*node
->func
) (file_vty
))
3127 vty_out (file_vty
, "!\n");
3129 vty_close (file_vty
);
3131 if (stat(config_file
, &conf_stat
) >= 0)
3133 if (unlink (config_file_sav
) != 0)
3134 if (errno
!= ENOENT
)
3136 vty_out (vty
, "Can't unlink backup configuration file %s.%s", config_file_sav
,
3140 if (link (config_file
, config_file_sav
) != 0)
3142 vty_out (vty
, "Can't backup old configuration file %s.%s", config_file_sav
,
3147 if (unlink (config_file
) != 0)
3149 vty_out (vty
, "Can't unlink configuration file %s.%s", config_file
,
3154 if (link (config_file_tmp
, config_file
) != 0)
3156 vty_out (vty
, "Can't save configuration file %s.%s", config_file
,
3162 if (chmod (config_file
, CONFIGFILE_MASK
) != 0)
3164 vty_out (vty
, "Can't chmod configuration file %s: %s (%d).%s",
3165 config_file
, safe_strerror(errno
), errno
, VTY_NEWLINE
);
3169 vty_out (vty
, "Configuration saved to %s%s", config_file
,
3174 unlink (config_file_tmp
);
3175 XFREE (MTYPE_TMP
, config_file_tmp
);
3176 XFREE (MTYPE_TMP
, config_file_sav
);
3180 ALIAS (config_write_file
,
3183 "Write running configuration to memory, network, or terminal\n")
3185 ALIAS (config_write_file
,
3186 config_write_memory_cmd
,
3188 "Write running configuration to memory, network, or terminal\n"
3189 "Write configuration to the file (same as write file)\n")
3191 ALIAS (config_write_file
,
3192 copy_runningconfig_startupconfig_cmd
,
3193 "copy running-config startup-config",
3194 "Copy configuration\n"
3195 "Copy running config to... \n"
3196 "Copy running config to startup config (same as write file)\n")
3198 /* Write current configuration into the terminal. */
3199 DEFUN (config_write_terminal
,
3200 config_write_terminal_cmd
,
3202 "Write running configuration to memory, network, or terminal\n"
3203 "Write to terminal\n")
3206 struct cmd_node
*node
;
3208 if (vty
->type
== VTY_SHELL_SERV
)
3210 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3211 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
&& node
->vtysh
)
3213 if ((*node
->func
) (vty
))
3214 vty_out (vty
, "!%s", VTY_NEWLINE
);
3219 vty_out (vty
, "%sCurrent configuration:%s", VTY_NEWLINE
,
3221 vty_out (vty
, "!%s", VTY_NEWLINE
);
3223 for (i
= 0; i
< vector_active (cmdvec
); i
++)
3224 if ((node
= vector_slot (cmdvec
, i
)) && node
->func
)
3226 if ((*node
->func
) (vty
))
3227 vty_out (vty
, "!%s", VTY_NEWLINE
);
3229 vty_out (vty
, "end%s",VTY_NEWLINE
);
3234 /* Write current configuration into the terminal. */
3235 ALIAS (config_write_terminal
,
3236 show_running_config_cmd
,
3237 "show running-config",
3239 "running configuration\n")
3241 /* Write startup configuration into the terminal. */
3242 DEFUN (show_startup_config
,
3243 show_startup_config_cmd
,
3244 "show startup-config",
3246 "Contentes of startup configuration\n")
3251 confp
= fopen (host
.config
, "r");
3254 vty_out (vty
, "Can't open configuration file [%s]%s",
3255 host
.config
, VTY_NEWLINE
);
3259 while (fgets (buf
, BUFSIZ
, confp
))
3263 while (*cp
!= '\r' && *cp
!= '\n' && *cp
!= '\0')
3267 vty_out (vty
, "%s%s", buf
, VTY_NEWLINE
);
3275 /* Hostname configuration */
3276 DEFUN (config_hostname
,
3279 "Set system's network name\n"
3280 "This system's network name\n")
3282 if (!isalpha((int) *argv
[0]))
3284 vty_out (vty
, "Please specify string starting with alphabet%s", VTY_NEWLINE
);
3289 XFREE (MTYPE_HOST
, host
.name
);
3291 host
.name
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3295 DEFUN (config_no_hostname
,
3297 "no hostname [HOSTNAME]",
3299 "Reset system's network name\n"
3300 "Host name of this router\n")
3303 XFREE (MTYPE_HOST
, host
.name
);
3308 /* VTY interface password set. */
3309 DEFUN (config_password
, password_cmd
,
3310 "password (8|) WORD",
3311 "Assign the terminal connection password\n"
3312 "Specifies a HIDDEN password will follow\n"
3314 "The HIDDEN line password string\n")
3316 /* Argument check. */
3319 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3325 if (*argv
[0] == '8')
3328 XFREE (MTYPE_HOST
, host
.password
);
3329 host
.password
= NULL
;
3330 if (host
.password_encrypt
)
3331 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3332 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3337 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3342 if (!isalnum ((int) *argv
[0]))
3345 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3350 XFREE (MTYPE_HOST
, host
.password
);
3351 host
.password
= NULL
;
3355 if (host
.password_encrypt
)
3356 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3357 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3360 host
.password
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3365 ALIAS (config_password
, password_text_cmd
,
3367 "Assign the terminal connection password\n"
3368 "The UNENCRYPTED (cleartext) line password\n")
3370 /* VTY enable password set. */
3371 DEFUN (config_enable_password
, enable_password_cmd
,
3372 "enable password (8|) WORD",
3373 "Modify enable password parameters\n"
3374 "Assign the privileged level password\n"
3375 "Specifies a HIDDEN password will follow\n"
3377 "The HIDDEN 'enable' password string\n")
3379 /* Argument check. */
3382 vty_out (vty
, "Please specify password.%s", VTY_NEWLINE
);
3386 /* Crypt type is specified. */
3389 if (*argv
[0] == '8')
3392 XFREE (MTYPE_HOST
, host
.enable
);
3395 if (host
.enable_encrypt
)
3396 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3397 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, argv
[1]);
3403 vty_out (vty
, "Unknown encryption type.%s", VTY_NEWLINE
);
3408 if (!isalnum ((int) *argv
[0]))
3411 "Please specify string starting with alphanumeric%s", VTY_NEWLINE
);
3416 XFREE (MTYPE_HOST
, host
.enable
);
3419 /* Plain password input. */
3422 if (host
.enable_encrypt
)
3423 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3424 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (argv
[0]));
3427 host
.enable
= XSTRDUP (MTYPE_HOST
, argv
[0]);
3432 ALIAS (config_enable_password
,
3433 enable_password_text_cmd
,
3434 "enable password LINE",
3435 "Modify enable password parameters\n"
3436 "Assign the privileged level password\n"
3437 "The UNENCRYPTED (cleartext) 'enable' password\n")
3439 /* VTY enable password delete. */
3440 DEFUN (no_config_enable_password
, no_enable_password_cmd
,
3441 "no enable password",
3443 "Modify enable password parameters\n"
3444 "Assign the privileged level password\n")
3447 XFREE (MTYPE_HOST
, host
.enable
);
3450 if (host
.enable_encrypt
)
3451 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3452 host
.enable_encrypt
= NULL
;
3457 DEFUN (service_password_encrypt
,
3458 service_password_encrypt_cmd
,
3459 "service password-encryption",
3460 "Set up miscellaneous service\n"
3461 "Enable encrypted passwords\n")
3470 if (host
.password_encrypt
)
3471 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3472 host
.password_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.password
));
3476 if (host
.enable_encrypt
)
3477 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3478 host
.enable_encrypt
= XSTRDUP (MTYPE_HOST
, zencrypt (host
.enable
));
3484 DEFUN (no_service_password_encrypt
,
3485 no_service_password_encrypt_cmd
,
3486 "no service password-encryption",
3488 "Set up miscellaneous service\n"
3489 "Enable encrypted passwords\n")
3496 if (host
.password_encrypt
)
3497 XFREE (MTYPE_HOST
, host
.password_encrypt
);
3498 host
.password_encrypt
= NULL
;
3500 if (host
.enable_encrypt
)
3501 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
3502 host
.enable_encrypt
= NULL
;
3507 DEFUN (config_terminal_length
, config_terminal_length_cmd
,
3508 "terminal length <0-512>",
3509 "Set terminal line parameters\n"
3510 "Set number of lines on a screen\n"
3511 "Number of lines on screen (0 for no pausing)\n")
3514 char *endptr
= NULL
;
3516 lines
= strtol (argv
[0], &endptr
, 10);
3517 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3519 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3527 DEFUN (config_terminal_no_length
, config_terminal_no_length_cmd
,
3528 "terminal no length",
3529 "Set terminal line parameters\n"
3531 "Set number of lines on a screen\n")
3537 DEFUN (service_terminal_length
, service_terminal_length_cmd
,
3538 "service terminal-length <0-512>",
3539 "Set up miscellaneous service\n"
3540 "System wide terminal length configuration\n"
3541 "Number of lines of VTY (0 means no line control)\n")
3544 char *endptr
= NULL
;
3546 lines
= strtol (argv
[0], &endptr
, 10);
3547 if (lines
< 0 || lines
> 512 || *endptr
!= '\0')
3549 vty_out (vty
, "length is malformed%s", VTY_NEWLINE
);
3557 DEFUN (no_service_terminal_length
, no_service_terminal_length_cmd
,
3558 "no service terminal-length [<0-512>]",
3560 "Set up miscellaneous service\n"
3561 "System wide terminal length configuration\n"
3562 "Number of lines of VTY (0 means no line control)\n")
3568 DEFUN_HIDDEN (do_echo
,
3571 "Echo a message back to the vty\n"
3572 "The message to echo\n")
3576 vty_out (vty
, "%s%s", ((message
= argv_concat(argv
, argc
, 0)) ? message
: ""),
3579 XFREE(MTYPE_TMP
, message
);
3583 DEFUN (config_logmsg
,
3585 "logmsg "LOG_LEVELS
" .MESSAGE",
3586 "Send a message to enabled logging destinations\n"
3588 "The message to send\n")
3593 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3594 return CMD_ERR_NO_MATCH
;
3596 zlog(NULL
, level
, "%s", ((message
= argv_concat(argv
, argc
, 1)) ? message
: ""));
3598 XFREE(MTYPE_TMP
, message
);
3602 DEFUN (show_logging
,
3606 "Show current logging configuration\n")
3608 struct zlog
*zl
= zlog_default
;
3610 vty_out (vty
, "Syslog logging: ");
3611 if (zl
->maxlvl
[ZLOG_DEST_SYSLOG
] == ZLOG_DISABLED
)
3612 vty_out (vty
, "disabled");
3614 vty_out (vty
, "level %s, facility %s, ident %s",
3615 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_SYSLOG
]],
3616 facility_name(zl
->facility
), zl
->ident
);
3617 vty_out (vty
, "%s", VTY_NEWLINE
);
3619 vty_out (vty
, "Stdout logging: ");
3620 if (zl
->maxlvl
[ZLOG_DEST_STDOUT
] == ZLOG_DISABLED
)
3621 vty_out (vty
, "disabled");
3623 vty_out (vty
, "level %s",
3624 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_STDOUT
]]);
3625 vty_out (vty
, "%s", VTY_NEWLINE
);
3627 vty_out (vty
, "Monitor logging: ");
3628 if (zl
->maxlvl
[ZLOG_DEST_MONITOR
] == ZLOG_DISABLED
)
3629 vty_out (vty
, "disabled");
3631 vty_out (vty
, "level %s",
3632 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_MONITOR
]]);
3633 vty_out (vty
, "%s", VTY_NEWLINE
);
3635 vty_out (vty
, "File logging: ");
3636 if ((zl
->maxlvl
[ZLOG_DEST_FILE
] == ZLOG_DISABLED
) ||
3638 vty_out (vty
, "disabled");
3640 vty_out (vty
, "level %s, filename %s",
3641 zlog_priority
[zl
->maxlvl
[ZLOG_DEST_FILE
]],
3643 vty_out (vty
, "%s", VTY_NEWLINE
);
3645 vty_out (vty
, "Protocol name: %s%s",
3646 zlog_proto_names
[zl
->protocol
], VTY_NEWLINE
);
3647 vty_out (vty
, "Record priority: %s%s",
3648 (zl
->record_priority
? "enabled" : "disabled"), VTY_NEWLINE
);
3649 vty_out (vty
, "Timestamp precision: %d%s",
3650 zl
->timestamp_precision
, VTY_NEWLINE
);
3655 DEFUN (config_log_stdout
,
3656 config_log_stdout_cmd
,
3659 "Set stdout logging level\n")
3661 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, zlog_default
->default_lvl
);
3665 DEFUN (config_log_stdout_level
,
3666 config_log_stdout_level_cmd
,
3667 "log stdout "LOG_LEVELS
,
3669 "Set stdout logging level\n"
3674 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3675 return CMD_ERR_NO_MATCH
;
3676 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, level
);
3680 DEFUN (no_config_log_stdout
,
3681 no_config_log_stdout_cmd
,
3682 "no log stdout [LEVEL]",
3685 "Cancel logging to stdout\n"
3688 zlog_set_level (NULL
, ZLOG_DEST_STDOUT
, ZLOG_DISABLED
);
3692 DEFUN (config_log_monitor
,
3693 config_log_monitor_cmd
,
3696 "Set terminal line (monitor) logging level\n")
3698 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, zlog_default
->default_lvl
);
3702 DEFUN (config_log_monitor_level
,
3703 config_log_monitor_level_cmd
,
3704 "log monitor "LOG_LEVELS
,
3706 "Set terminal line (monitor) logging level\n"
3711 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3712 return CMD_ERR_NO_MATCH
;
3713 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, level
);
3717 DEFUN (no_config_log_monitor
,
3718 no_config_log_monitor_cmd
,
3719 "no log monitor [LEVEL]",
3722 "Disable terminal line (monitor) logging\n"
3725 zlog_set_level (NULL
, ZLOG_DEST_MONITOR
, ZLOG_DISABLED
);
3730 set_log_file(struct vty
*vty
, const char *fname
, int loglevel
)
3734 const char *fullpath
;
3736 /* Path detection. */
3737 if (! IS_DIRECTORY_SEP (*fname
))
3739 char cwd
[MAXPATHLEN
+1];
3740 cwd
[MAXPATHLEN
] = '\0';
3742 if (getcwd (cwd
, MAXPATHLEN
) == NULL
)
3744 zlog_err ("config_log_file: Unable to alloc mem!");
3748 if ( (p
= XMALLOC (MTYPE_TMP
, strlen (cwd
) + strlen (fname
) + 2))
3751 zlog_err ("config_log_file: Unable to alloc mem!");
3754 sprintf (p
, "%s/%s", cwd
, fname
);
3760 ret
= zlog_set_file (NULL
, fullpath
, loglevel
);
3763 XFREE (MTYPE_TMP
, p
);
3767 vty_out (vty
, "can't open logfile %s\n", fname
);
3772 XFREE (MTYPE_HOST
, host
.logfile
);
3774 host
.logfile
= XSTRDUP (MTYPE_HOST
, fname
);
3779 DEFUN (config_log_file
,
3780 config_log_file_cmd
,
3781 "log file FILENAME",
3784 "Logging filename\n")
3786 return set_log_file(vty
, argv
[0], zlog_default
->default_lvl
);
3789 DEFUN (config_log_file_level
,
3790 config_log_file_level_cmd
,
3791 "log file FILENAME "LOG_LEVELS
,
3794 "Logging filename\n"
3799 if ((level
= level_match(argv
[1])) == ZLOG_DISABLED
)
3800 return CMD_ERR_NO_MATCH
;
3801 return set_log_file(vty
, argv
[0], level
);
3804 DEFUN (no_config_log_file
,
3805 no_config_log_file_cmd
,
3806 "no log file [FILENAME]",
3809 "Cancel logging to file\n"
3810 "Logging file name\n")
3812 zlog_reset_file (NULL
);
3815 XFREE (MTYPE_HOST
, host
.logfile
);
3817 host
.logfile
= NULL
;
3822 ALIAS (no_config_log_file
,
3823 no_config_log_file_level_cmd
,
3824 "no log file FILENAME LEVEL",
3827 "Cancel logging to file\n"
3828 "Logging file name\n"
3831 DEFUN (config_log_syslog
,
3832 config_log_syslog_cmd
,
3835 "Set syslog logging level\n")
3837 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3841 DEFUN (config_log_syslog_level
,
3842 config_log_syslog_level_cmd
,
3843 "log syslog "LOG_LEVELS
,
3845 "Set syslog logging level\n"
3850 if ((level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3851 return CMD_ERR_NO_MATCH
;
3852 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, level
);
3856 DEFUN_DEPRECATED (config_log_syslog_facility
,
3857 config_log_syslog_facility_cmd
,
3858 "log syslog facility "LOG_FACILITIES
,
3860 "Logging goes to syslog\n"
3861 "(Deprecated) Facility parameter for syslog messages\n"
3866 if ((facility
= facility_match(argv
[0])) < 0)
3867 return CMD_ERR_NO_MATCH
;
3869 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, zlog_default
->default_lvl
);
3870 zlog_default
->facility
= facility
;
3874 DEFUN (no_config_log_syslog
,
3875 no_config_log_syslog_cmd
,
3876 "no log syslog [LEVEL]",
3879 "Cancel logging to syslog\n"
3882 zlog_set_level (NULL
, ZLOG_DEST_SYSLOG
, ZLOG_DISABLED
);
3886 ALIAS (no_config_log_syslog
,
3887 no_config_log_syslog_facility_cmd
,
3888 "no log syslog facility "LOG_FACILITIES
,
3891 "Logging goes to syslog\n"
3892 "Facility parameter for syslog messages\n"
3895 DEFUN (config_log_facility
,
3896 config_log_facility_cmd
,
3897 "log facility "LOG_FACILITIES
,
3899 "Facility parameter for syslog messages\n"
3904 if ((facility
= facility_match(argv
[0])) < 0)
3905 return CMD_ERR_NO_MATCH
;
3906 zlog_default
->facility
= facility
;
3910 DEFUN (no_config_log_facility
,
3911 no_config_log_facility_cmd
,
3912 "no log facility [FACILITY]",
3915 "Reset syslog facility to default (daemon)\n"
3916 "Syslog facility\n")
3918 zlog_default
->facility
= LOG_DAEMON
;
3922 DEFUN_DEPRECATED (config_log_trap
,
3923 config_log_trap_cmd
,
3924 "log trap "LOG_LEVELS
,
3926 "(Deprecated) Set logging level and default for all destinations\n"
3932 if ((new_level
= level_match(argv
[0])) == ZLOG_DISABLED
)
3933 return CMD_ERR_NO_MATCH
;
3935 zlog_default
->default_lvl
= new_level
;
3936 for (i
= 0; i
< ZLOG_NUM_DESTS
; i
++)
3937 if (zlog_default
->maxlvl
[i
] != ZLOG_DISABLED
)
3938 zlog_default
->maxlvl
[i
] = new_level
;
3942 DEFUN_DEPRECATED (no_config_log_trap
,
3943 no_config_log_trap_cmd
,
3944 "no log trap [LEVEL]",
3947 "Permit all logging information\n"
3950 zlog_default
->default_lvl
= LOG_DEBUG
;
3954 DEFUN (config_log_record_priority
,
3955 config_log_record_priority_cmd
,
3956 "log record-priority",
3958 "Log the priority of the message within the message\n")
3960 zlog_default
->record_priority
= 1 ;
3964 DEFUN (no_config_log_record_priority
,
3965 no_config_log_record_priority_cmd
,
3966 "no log record-priority",
3969 "Do not log the priority of the message within the message\n")
3971 zlog_default
->record_priority
= 0 ;
3975 DEFUN (config_log_timestamp_precision
,
3976 config_log_timestamp_precision_cmd
,
3977 "log timestamp precision <0-6>",
3979 "Timestamp configuration\n"
3980 "Set the timestamp precision\n"
3981 "Number of subsecond digits\n")
3985 vty_out (vty
, "Insufficient arguments%s", VTY_NEWLINE
);
3989 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3990 zlog_default
->timestamp_precision
, argv
[0], 0, 6);
3994 DEFUN (no_config_log_timestamp_precision
,
3995 no_config_log_timestamp_precision_cmd
,
3996 "no log timestamp precision",
3999 "Timestamp configuration\n"
4000 "Reset the timestamp precision to the default value of 0\n")
4002 zlog_default
->timestamp_precision
= 0 ;
4006 DEFUN (banner_motd_file
,
4007 banner_motd_file_cmd
,
4008 "banner motd file [FILE]",
4011 "Banner from a file\n"
4015 XFREE (MTYPE_HOST
, host
.motdfile
);
4016 host
.motdfile
= XSTRDUP (MTYPE_HOST
, argv
[0]);
4021 DEFUN (banner_motd_default
,
4022 banner_motd_default_cmd
,
4023 "banner motd default",
4024 "Set banner string\n"
4025 "Strings for motd\n"
4028 host
.motd
= default_motd
;
4032 DEFUN (no_banner_motd
,
4036 "Set banner string\n"
4037 "Strings for motd\n")
4041 XFREE (MTYPE_HOST
, host
.motdfile
);
4042 host
.motdfile
= NULL
;
4046 /* Set config filename. Called from vty.c */
4048 host_config_set (const char *filename
)
4051 XFREE (MTYPE_HOST
, host
.config
);
4052 host
.config
= XSTRDUP (MTYPE_HOST
, filename
);
4056 install_default (enum node_type node
)
4058 install_element (node
, &config_exit_cmd
);
4059 install_element (node
, &config_quit_cmd
);
4060 install_element (node
, &config_end_cmd
);
4061 install_element (node
, &config_help_cmd
);
4062 install_element (node
, &config_list_cmd
);
4064 install_element (node
, &config_write_terminal_cmd
);
4065 install_element (node
, &config_write_file_cmd
);
4066 install_element (node
, &config_write_memory_cmd
);
4067 install_element (node
, &config_write_cmd
);
4068 install_element (node
, &show_running_config_cmd
);
4071 /* Initialize command interface. Install basic nodes and commands. */
4073 cmd_init (int terminal
)
4075 command_cr
= XSTRDUP(MTYPE_CMD_TOKENS
, "<cr>");
4076 token_cr
.type
= TOKEN_TERMINAL
;
4077 token_cr
.cmd
= command_cr
;
4078 token_cr
.desc
= XSTRDUP(MTYPE_CMD_TOKENS
, "");
4080 /* Allocate initial top vector of commands. */
4081 cmdvec
= vector_init (VECTOR_MIN_SIZE
);
4083 /* Default host value settings. */
4085 host
.password
= NULL
;
4087 host
.logfile
= NULL
;
4090 host
.motd
= default_motd
;
4091 host
.motdfile
= NULL
;
4093 /* Install top nodes. */
4094 install_node (&view_node
, NULL
);
4095 install_node (&enable_node
, NULL
);
4096 install_node (&auth_node
, NULL
);
4097 install_node (&auth_enable_node
, NULL
);
4098 install_node (&restricted_node
, NULL
);
4099 install_node (&config_node
, config_write_host
);
4101 /* Each node's basic commands. */
4102 install_element (VIEW_NODE
, &show_version_cmd
);
4105 install_element (VIEW_NODE
, &config_list_cmd
);
4106 install_element (VIEW_NODE
, &config_exit_cmd
);
4107 install_element (VIEW_NODE
, &config_quit_cmd
);
4108 install_element (VIEW_NODE
, &config_help_cmd
);
4109 install_element (VIEW_NODE
, &config_enable_cmd
);
4110 install_element (VIEW_NODE
, &config_terminal_length_cmd
);
4111 install_element (VIEW_NODE
, &config_terminal_no_length_cmd
);
4112 install_element (VIEW_NODE
, &show_logging_cmd
);
4113 install_element (VIEW_NODE
, &echo_cmd
);
4115 install_element (RESTRICTED_NODE
, &config_list_cmd
);
4116 install_element (RESTRICTED_NODE
, &config_exit_cmd
);
4117 install_element (RESTRICTED_NODE
, &config_quit_cmd
);
4118 install_element (RESTRICTED_NODE
, &config_help_cmd
);
4119 install_element (RESTRICTED_NODE
, &config_enable_cmd
);
4120 install_element (RESTRICTED_NODE
, &config_terminal_length_cmd
);
4121 install_element (RESTRICTED_NODE
, &config_terminal_no_length_cmd
);
4122 install_element (RESTRICTED_NODE
, &echo_cmd
);
4127 install_default (ENABLE_NODE
);
4128 install_element (ENABLE_NODE
, &config_disable_cmd
);
4129 install_element (ENABLE_NODE
, &config_terminal_cmd
);
4130 install_element (ENABLE_NODE
, ©_runningconfig_startupconfig_cmd
);
4132 install_element (ENABLE_NODE
, &show_startup_config_cmd
);
4133 install_element (ENABLE_NODE
, &show_version_cmd
);
4137 install_element (ENABLE_NODE
, &config_terminal_length_cmd
);
4138 install_element (ENABLE_NODE
, &config_terminal_no_length_cmd
);
4139 install_element (ENABLE_NODE
, &show_logging_cmd
);
4140 install_element (ENABLE_NODE
, &echo_cmd
);
4141 install_element (ENABLE_NODE
, &config_logmsg_cmd
);
4143 install_default (CONFIG_NODE
);
4146 install_element (CONFIG_NODE
, &hostname_cmd
);
4147 install_element (CONFIG_NODE
, &no_hostname_cmd
);
4151 install_element (CONFIG_NODE
, &password_cmd
);
4152 install_element (CONFIG_NODE
, &password_text_cmd
);
4153 install_element (CONFIG_NODE
, &enable_password_cmd
);
4154 install_element (CONFIG_NODE
, &enable_password_text_cmd
);
4155 install_element (CONFIG_NODE
, &no_enable_password_cmd
);
4157 install_element (CONFIG_NODE
, &config_log_stdout_cmd
);
4158 install_element (CONFIG_NODE
, &config_log_stdout_level_cmd
);
4159 install_element (CONFIG_NODE
, &no_config_log_stdout_cmd
);
4160 install_element (CONFIG_NODE
, &config_log_monitor_cmd
);
4161 install_element (CONFIG_NODE
, &config_log_monitor_level_cmd
);
4162 install_element (CONFIG_NODE
, &no_config_log_monitor_cmd
);
4163 install_element (CONFIG_NODE
, &config_log_file_cmd
);
4164 install_element (CONFIG_NODE
, &config_log_file_level_cmd
);
4165 install_element (CONFIG_NODE
, &no_config_log_file_cmd
);
4166 install_element (CONFIG_NODE
, &no_config_log_file_level_cmd
);
4167 install_element (CONFIG_NODE
, &config_log_syslog_cmd
);
4168 install_element (CONFIG_NODE
, &config_log_syslog_level_cmd
);
4169 install_element (CONFIG_NODE
, &config_log_syslog_facility_cmd
);
4170 install_element (CONFIG_NODE
, &no_config_log_syslog_cmd
);
4171 install_element (CONFIG_NODE
, &no_config_log_syslog_facility_cmd
);
4172 install_element (CONFIG_NODE
, &config_log_facility_cmd
);
4173 install_element (CONFIG_NODE
, &no_config_log_facility_cmd
);
4174 install_element (CONFIG_NODE
, &config_log_trap_cmd
);
4175 install_element (CONFIG_NODE
, &no_config_log_trap_cmd
);
4176 install_element (CONFIG_NODE
, &config_log_record_priority_cmd
);
4177 install_element (CONFIG_NODE
, &no_config_log_record_priority_cmd
);
4178 install_element (CONFIG_NODE
, &config_log_timestamp_precision_cmd
);
4179 install_element (CONFIG_NODE
, &no_config_log_timestamp_precision_cmd
);
4180 install_element (CONFIG_NODE
, &service_password_encrypt_cmd
);
4181 install_element (CONFIG_NODE
, &no_service_password_encrypt_cmd
);
4182 install_element (CONFIG_NODE
, &banner_motd_default_cmd
);
4183 install_element (CONFIG_NODE
, &banner_motd_file_cmd
);
4184 install_element (CONFIG_NODE
, &no_banner_motd_cmd
);
4185 install_element (CONFIG_NODE
, &service_terminal_length_cmd
);
4186 install_element (CONFIG_NODE
, &no_service_terminal_length_cmd
);
4188 install_element (VIEW_NODE
, &show_thread_cpu_cmd
);
4189 install_element (ENABLE_NODE
, &show_thread_cpu_cmd
);
4190 install_element (RESTRICTED_NODE
, &show_thread_cpu_cmd
);
4192 install_element (ENABLE_NODE
, &clear_thread_cpu_cmd
);
4193 install_element (VIEW_NODE
, &show_work_queues_cmd
);
4194 install_element (ENABLE_NODE
, &show_work_queues_cmd
);
4200 cmd_terminate_token(struct cmd_token
*token
)
4203 vector keyword_vect
;
4205 if (token
->multiple
)
4207 for (i
= 0; i
< vector_active(token
->multiple
); i
++)
4208 cmd_terminate_token(vector_slot(token
->multiple
, i
));
4209 vector_free(token
->multiple
);
4210 token
->multiple
= NULL
;
4215 for (i
= 0; i
< vector_active(token
->keyword
); i
++)
4217 keyword_vect
= vector_slot(token
->keyword
, i
);
4218 for (j
= 0; j
< vector_active(keyword_vect
); j
++)
4219 cmd_terminate_token(vector_slot(keyword_vect
, j
));
4220 vector_free(keyword_vect
);
4222 vector_free(token
->keyword
);
4223 token
->keyword
= NULL
;
4226 XFREE(MTYPE_CMD_TOKENS
, token
->cmd
);
4227 XFREE(MTYPE_CMD_TOKENS
, token
->desc
);
4229 XFREE(MTYPE_CMD_TOKENS
, token
);
4233 cmd_terminate_element(struct cmd_element
*cmd
)
4237 if (cmd
->tokens
== NULL
)
4240 for (i
= 0; i
< vector_active(cmd
->tokens
); i
++)
4241 cmd_terminate_token(vector_slot(cmd
->tokens
, i
));
4243 vector_free(cmd
->tokens
);
4251 struct cmd_node
*cmd_node
;
4252 struct cmd_element
*cmd_element
;
4257 for (i
= 0; i
< vector_active (cmdvec
); i
++)
4258 if ((cmd_node
= vector_slot (cmdvec
, i
)) != NULL
)
4260 cmd_node_v
= cmd_node
->cmd_vector
;
4262 for (j
= 0; j
< vector_active (cmd_node_v
); j
++)
4263 if ((cmd_element
= vector_slot (cmd_node_v
, j
)) != NULL
)
4264 cmd_terminate_element(cmd_element
);
4266 vector_free (cmd_node_v
);
4269 vector_free (cmdvec
);
4274 XFREE(MTYPE_CMD_TOKENS
, command_cr
);
4276 XFREE(MTYPE_CMD_TOKENS
, token_cr
.desc
);
4278 XFREE (MTYPE_HOST
, host
.name
);
4280 XFREE (MTYPE_HOST
, host
.password
);
4281 if (host
.password_encrypt
)
4282 XFREE (MTYPE_HOST
, host
.password_encrypt
);
4284 XFREE (MTYPE_HOST
, host
.enable
);
4285 if (host
.enable_encrypt
)
4286 XFREE (MTYPE_HOST
, host
.enable_encrypt
);
4288 XFREE (MTYPE_HOST
, host
.logfile
);
4290 XFREE (MTYPE_HOST
, host
.motdfile
);
4292 XFREE (MTYPE_HOST
, host
.config
);