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);
184 printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
188 /* Utility function to concatenate argv argument into a single string
189 with inserting ' ' character between each argument. */
191 argv_concat (const char **argv, int argc, int shift)
199 for (i = shift; i < argc; i++)
200 len += strlen(argv[i])+1;
203 p = str = XMALLOC(MTYPE_TMP, len);
204 for (i = shift; i < argc; i++)
207 memcpy(p, argv[i], (arglen = strlen(argv[i])));
216 cmd_hash_key (void *p)
218 return (uintptr_t) p;
222 cmd_hash_cmp (const void *a, const void *b)
227 /* Install top node of command vector. */
229 install_node (struct cmd_node *node,
230 int (*func) (struct vty *))
232 vector_set_index (cmdvec, node->node, node);
234 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
235 node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
238 /* Breaking up string into each command piece. I assume given
239 character is separated by a space character. Return value is a
240 vector which includes char ** data element. */
242 cmd_make_strvec (const char *string)
244 const char *cp, *start;
254 /* Skip white spaces. */
255 while (isspace ((int) *cp) && *cp != '\0')
258 /* Return if there is only white spaces */
262 if (*cp == '!' || *cp == '#')
265 /* Prepare return vector. */
266 strvec = vector_init (VECTOR_MIN_SIZE);
268 /* Copy each command piece and set into vector. */
272 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
276 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
277 memcpy (token, start, strlen);
278 *(token + strlen) = '\0';
279 vector_set (strvec, token);
281 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
290 /* Free allocated string vector. */
292 cmd_free_strvec (vector v)
300 for (i = 0; i < vector_active (v); i++)
301 if ((cp = vector_slot (v, i)) != NULL)
302 XFREE (MTYPE_STRVEC, cp);
307 struct format_parser_state
309 vector topvect; /* Top level vector */
310 vector intvect; /* Intermediate level vector, used when there's
311 * a multiple in a keyword. */
312 vector curvect; /* current vector where read tokens should be
315 const char *string; /* pointer to command string, not modified */
316 const char *cp; /* pointer in command string, moved along while
318 const char *dp; /* pointer in description string, moved along while
321 int in_keyword; /* flag to remember if we are in a keyword group */
322 int in_multiple; /* flag to remember if we are in a multiple group */
323 int just_read_word; /* flag to remember if the last thing we red was a
324 * real word and not some abstract token */
328 format_parser_error(struct format_parser_state *state, const char *message)
330 int offset = state->cp - state->string + 1;
332 fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
333 fprintf(stderr, " %*c\n", offset, '^');
334 fprintf(stderr, "%s at offset %d.\n", message, offset);
335 fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
340 format_parser_desc_str(struct format_parser_state *state)
342 const char *cp, *start;
351 /* Skip white spaces. */
352 while (isspace ((int) *cp) && *cp != '\0')
355 /* Return if there is only white spaces */
361 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
365 token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
366 memcpy (token, start, strlen);
367 *(token + strlen) = '\0';
375 format_parser_begin_keyword(struct format_parser_state *state)
377 struct cmd_token *token;
380 if (state->in_keyword
381 || state->in_multiple)
382 format_parser_error(state, "Unexpected '{'");
385 state->in_keyword = 1;
387 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
388 token->type = TOKEN_KEYWORD;
389 token->keyword = vector_init(VECTOR_MIN_SIZE);
391 keyword_vect = vector_init(VECTOR_MIN_SIZE);
392 vector_set(token->keyword, keyword_vect);
394 vector_set(state->curvect, token);
395 state->curvect = keyword_vect;
399 format_parser_begin_multiple(struct format_parser_state *state)
401 struct cmd_token *token;
403 if (state->in_keyword == 1)
404 format_parser_error(state, "Keyword starting with '('");
406 if (state->in_multiple)
407 format_parser_error(state, "Nested group");
410 state->in_multiple = 1;
411 state->just_read_word = 0;
413 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
414 token->type = TOKEN_MULTIPLE;
415 token->multiple = vector_init(VECTOR_MIN_SIZE);
417 vector_set(state->curvect, token);
418 if (state->curvect != state->topvect)
419 state->intvect = state->curvect;
420 state->curvect = token->multiple;
424 format_parser_end_keyword(struct format_parser_state *state)
426 if (state->in_multiple
427 || !state->in_keyword)
428 format_parser_error(state, "Unexpected '}'");
430 if (state->in_keyword == 1)
431 format_parser_error(state, "Empty keyword group");
434 state->in_keyword = 0;
435 state->curvect = state->topvect;
439 format_parser_end_multiple(struct format_parser_state *state)
443 if (!state->in_multiple)
444 format_parser_error(state, "Unexpected ')'");
446 if (vector_active(state->curvect) == 0)
447 format_parser_error(state, "Empty multiple section");
449 if (!state->just_read_word)
451 /* There are constructions like
452 * 'show ip ospf database ... (self-originate|)'
454 * The old parser reads a description string for the
455 * word '' between |) which will never match.
456 * Simulate this behvaior by dropping the next desc
457 * string in such a case. */
459 dummy = format_parser_desc_str(state);
460 XFREE(MTYPE_CMD_TOKENS, dummy);
464 state->in_multiple = 0;
467 state->curvect = state->intvect;
469 state->curvect = state->topvect;
473 format_parser_handle_pipe(struct format_parser_state *state)
475 struct cmd_token *keyword_token;
478 if (state->in_multiple)
480 state->just_read_word = 0;
483 else if (state->in_keyword)
485 state->in_keyword = 1;
488 keyword_token = vector_slot(state->topvect,
489 vector_active(state->topvect) - 1);
490 keyword_vect = vector_init(VECTOR_MIN_SIZE);
491 vector_set(keyword_token->keyword, keyword_vect);
492 state->curvect = keyword_vect;
496 format_parser_error(state, "Unexpected '|'");
501 format_parser_read_word(struct format_parser_state *state)
506 struct cmd_token *token;
510 while (state->cp[0] != '\0'
511 && !strchr("\r\n(){}|", state->cp[0])
512 && !isspace((int)state->cp[0]))
515 len = state->cp - start;
516 cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
517 memcpy(cmd, start, len);
520 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
521 token->type = TOKEN_TERMINAL;
522 if (strcmp (cmd, "A.B.C.D") == 0)
523 token->terminal = TERMINAL_IPV4;
524 else if (strcmp (cmd, "A.B.C.D/M") == 0)
525 token->terminal = TERMINAL_IPV4_PREFIX;
526 else if (strcmp (cmd, "X:X::X:X") == 0)
527 token->terminal = TERMINAL_IPV6;
528 else if (strcmp (cmd, "X:X::X:X/M") == 0)
529 token->terminal = TERMINAL_IPV6_PREFIX;
530 else if (cmd[0] == '[')
531 token->terminal = TERMINAL_OPTION;
532 else if (cmd[0] == '.')
533 token->terminal = TERMINAL_VARARG;
534 else if (cmd[0] == '<')
535 token->terminal = TERMINAL_RANGE;
536 else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
537 token->terminal = TERMINAL_VARIABLE;
539 token->terminal = TERMINAL_LITERAL;
542 token->desc = format_parser_desc_str(state);
543 vector_set(state->curvect, token);
545 if (state->in_keyword == 1)
546 state->in_keyword = 2;
548 state->just_read_word = 1;
552 * Parse a given command format string and build a tree of tokens from
553 * it that is suitable to be used by the command subsystem.
555 * @param string Command format string.
556 * @param descstr Description string.
557 * @return A vector of struct cmd_token representing the given command,
561 cmd_parse_format(const char *string, const char *descstr)
563 struct format_parser_state state;
568 memset(&state, 0, sizeof(state));
569 state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
570 state.cp = state.string = string;
575 while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
582 || state.in_multiple)
583 format_parser_error(&state, "Unclosed group/keyword");
584 return state.topvect;
586 format_parser_begin_keyword(&state);
589 format_parser_begin_multiple(&state);
592 format_parser_end_keyword(&state);
595 format_parser_end_multiple(&state);
598 format_parser_handle_pipe(&state);
601 format_parser_read_word(&state);
606 /* Return prompt character of specified node. */
608 cmd_prompt (enum node_type node)
610 struct cmd_node *cnode;
612 cnode = vector_slot (cmdvec, node);
613 return cnode->prompt;
616 /* Install a command into a node. */
618 install_element (enum node_type ntype, struct cmd_element *cmd)
620 struct cmd_node *cnode;
622 /* cmd_init hasn't been called */
625 fprintf (stderr, "%s called before cmd_init, breakage likely\n",
630 cnode = vector_slot (cmdvec, ntype);
634 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
639 if (hash_lookup (cnode->cmd_hash, cmd) != NULL)
643 "Multiple command installs to node %d of command:\n%s\n",
649 assert (hash_get (cnode->cmd_hash, cmd, hash_alloc_intern));
651 vector_set (cnode->cmd_vector, cmd);
652 if (cmd->tokens == NULL)
653 cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
655 if (ntype == VIEW_NODE)
656 install_element (ENABLE_NODE, cmd);
659 static const unsigned char itoa64[] =
660 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
663 to64(char *s, long v, int n)
667 *s++ = itoa64[v&0x3f];
673 zencrypt (const char *passwd)
677 char *crypt (const char *, const char *);
681 to64(&salt[0], random(), 3);
682 to64(&salt[3], tv.tv_usec, 3);
685 return crypt (passwd, salt);
688 /* This function write configuration of this host. */
690 config_write_host (struct vty *vty)
693 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
697 if (host.password_encrypt)
698 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
699 if (host.enable_encrypt)
700 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
705 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
707 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
710 if (zlog_default->default_lvl != LOG_DEBUG)
712 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
714 vty_out (vty, "log trap %s%s",
715 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
718 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
720 vty_out (vty, "log file %s", host.logfile);
721 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
723 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
724 vty_out (vty, "%s", VTY_NEWLINE);
727 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
729 vty_out (vty, "log stdout");
730 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
732 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
733 vty_out (vty, "%s", VTY_NEWLINE);
736 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
737 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
738 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
739 vty_out(vty,"log monitor %s%s",
740 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
742 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
744 vty_out (vty, "log syslog");
745 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
747 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
748 vty_out (vty, "%s", VTY_NEWLINE);
751 if (zlog_default->facility != LOG_DAEMON)
752 vty_out (vty, "log facility %s%s",
753 facility_name(zlog_default->facility), VTY_NEWLINE);
755 if (zlog_default->record_priority == 1)
756 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
758 if (zlog_default->timestamp_precision > 0)
759 vty_out (vty, "log timestamp precision %d%s",
760 zlog_default->timestamp_precision, VTY_NEWLINE);
763 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
766 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
769 vty_out (vty, "service terminal-length %d%s", host.lines,
773 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
774 else if (! host.motd)
775 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
780 /* Utility function for getting command vector. */
782 cmd_node_vector (vector v, enum node_type ntype)
784 struct cmd_node *cnode = vector_slot (v, ntype);
785 return cnode->cmd_vector;
788 /* Completion match types. */
803 static enum match_type
804 cmd_ipv4_match (const char *str)
807 int dots = 0, nums = 0;
815 memset (buf, 0, sizeof (buf));
824 if (*(str + 1) == '.')
827 if (*(str + 1) == '\0')
833 if (!isdigit ((int) *str))
842 strncpy (buf, sp, str - sp);
843 if (atoi (buf) > 255)
860 static enum match_type
861 cmd_ipv4_prefix_match (const char *str)
872 memset (buf, 0, sizeof (buf));
874 while (*str != '\0' && *str != '/')
881 if (*(str + 1) == '.' || *(str + 1) == '/')
884 if (*(str + 1) == '\0')
891 if (!isdigit ((int) *str))
900 strncpy (buf, sp, str - sp);
901 if (atoi (buf) > 255)
908 if (*(str + 1) == '\0')
914 else if (*str == '\0')
927 if (!isdigit ((int) *str))
939 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
940 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
941 #define STATE_START 1
942 #define STATE_COLON 2
943 #define STATE_DOUBLE 3
946 #define STATE_SLASH 6
951 static enum match_type
952 cmd_ipv6_match (const char *str)
954 struct sockaddr_in6 sin6_dummy;
960 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
963 /* use inet_pton that has a better support,
964 * for example inet_pton can support the automatic addresses:
967 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
975 static enum match_type
976 cmd_ipv6_prefix_match (const char *str)
978 int state = STATE_START;
979 int colons = 0, nums = 0, double_colon = 0;
981 const char *sp = NULL;
987 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
990 while (*str != '\0' && state != STATE_MASK)
997 if (*(str + 1) != ':' && *(str + 1) != '\0')
1000 state = STATE_COLON;
1011 if (*(str + 1) == '/')
1013 else if (*(str + 1) == ':')
1014 state = STATE_DOUBLE;
1025 if (*(str + 1) == ':')
1029 if (*(str + 1) != '\0' && *(str + 1) != '/')
1033 if (*(str + 1) == '/')
1034 state = STATE_SLASH;
1043 if (*(str + 1) == ':' || *(str + 1) == '.'
1044 || *(str + 1) == '\0' || *(str + 1) == '/')
1049 for (; sp <= str; sp++)
1055 if (*(str + 1) == ':')
1056 state = STATE_COLON;
1057 else if (*(str + 1) == '.')
1059 if (colons || double_colon)
1064 else if (*(str + 1) == '/')
1065 state = STATE_SLASH;
1072 if (*(str + 1) == '\0')
1073 return partly_match;
1090 if (state < STATE_MASK)
1091 return partly_match;
1093 mask = strtol (str, &endptr, 10);
1094 if (*endptr != '\0')
1097 if (mask < 0 || mask > 128)
1103 #endif /* HAVE_IPV6 */
1105 #define DECIMAL_STRLEN_MAX 10
1108 cmd_range_match (const char *range, const char *str)
1111 char buf[DECIMAL_STRLEN_MAX + 1];
1112 char *endptr = NULL;
1113 unsigned long min, max, val;
1118 val = strtoul (str, &endptr, 10);
1119 if (*endptr != '\0')
1123 p = strchr (range, '-');
1126 if (p - range > DECIMAL_STRLEN_MAX)
1128 strncpy (buf, range, p - range);
1129 buf[p - range] = '\0';
1130 min = strtoul (buf, &endptr, 10);
1131 if (*endptr != '\0')
1135 p = strchr (range, '>');
1138 if (p - range > DECIMAL_STRLEN_MAX)
1140 strncpy (buf, range, p - range);
1141 buf[p - range] = '\0';
1142 max = strtoul (buf, &endptr, 10);
1143 if (*endptr != '\0')
1146 if (val < min || val > max)
1152 static enum match_type
1153 cmd_word_match(struct cmd_token *token,
1154 enum filter_type filter,
1158 enum match_type match_type;
1162 if (filter == FILTER_RELAXED)
1163 if (!word || !strlen(word))
1164 return partly_match;
1169 switch (token->terminal)
1171 case TERMINAL_VARARG:
1172 return vararg_match;
1174 case TERMINAL_RANGE:
1175 if (cmd_range_match(str, word))
1180 match_type = cmd_ipv6_match(word);
1181 if ((filter == FILTER_RELAXED && match_type != no_match)
1182 || (filter == FILTER_STRICT && match_type == exact_match))
1186 case TERMINAL_IPV6_PREFIX:
1187 match_type = cmd_ipv6_prefix_match(word);
1188 if ((filter == FILTER_RELAXED && match_type != no_match)
1189 || (filter == FILTER_STRICT && match_type == exact_match))
1190 return ipv6_prefix_match;
1194 match_type = cmd_ipv4_match(word);
1195 if ((filter == FILTER_RELAXED && match_type != no_match)
1196 || (filter == FILTER_STRICT && match_type == exact_match))
1200 case TERMINAL_IPV4_PREFIX:
1201 match_type = cmd_ipv4_prefix_match(word);
1202 if ((filter == FILTER_RELAXED && match_type != no_match)
1203 || (filter == FILTER_STRICT && match_type == exact_match))
1204 return ipv4_prefix_match;
1207 case TERMINAL_OPTION:
1208 case TERMINAL_VARIABLE:
1209 return extend_match;
1211 case TERMINAL_LITERAL:
1212 if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
1214 if (!strcmp(str, word))
1216 return partly_match;
1218 if (filter == FILTER_STRICT && !strcmp(str, word))
1231 struct cmd_element *cmd; /* The command element the matcher is using */
1232 enum filter_type filter; /* Whether to use strict or relaxed matching */
1233 vector vline; /* The tokenized commandline which is to be matched */
1234 unsigned int index; /* The index up to which matching should be done */
1236 /* If set, construct a list of matches at the position given by index */
1237 enum match_type *match_type;
1240 unsigned int word_index; /* iterating over vline */
1244 push_argument(int *argc, const char **argv, const char *arg)
1246 if (!arg || !strlen(arg))
1252 if (*argc >= CMD_ARGC_MAX)
1255 argv[(*argc)++] = arg;
1260 cmd_matcher_record_match(struct cmd_matcher *matcher,
1261 enum match_type match_type,
1262 struct cmd_token *token)
1264 if (matcher->word_index != matcher->index)
1269 if (!*matcher->match)
1270 *matcher->match = vector_init(VECTOR_MIN_SIZE);
1271 vector_set(*matcher->match, token);
1274 if (matcher->match_type)
1276 if (match_type > *matcher->match_type)
1277 *matcher->match_type = match_type;
1282 cmd_matcher_words_left(struct cmd_matcher *matcher)
1284 return matcher->word_index < vector_active(matcher->vline);
1288 cmd_matcher_get_word(struct cmd_matcher *matcher)
1290 assert(cmd_matcher_words_left(matcher));
1292 return vector_slot(matcher->vline, matcher->word_index);
1295 static enum matcher_rv
1296 cmd_matcher_match_terminal(struct cmd_matcher *matcher,
1297 struct cmd_token *token,
1298 int *argc, const char **argv)
1301 enum match_type word_match;
1303 assert(token->type == TOKEN_TERMINAL);
1305 if (!cmd_matcher_words_left(matcher))
1307 if (token->terminal == TERMINAL_OPTION)
1308 return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
1310 return MATCHER_INCOMPLETE;
1313 word = cmd_matcher_get_word(matcher);
1314 word_match = cmd_word_match(token, matcher->filter, word);
1315 if (word_match == no_match)
1316 return MATCHER_NO_MATCH;
1318 /* We have to record the input word as argument if it matched
1319 * against a variable. */
1320 if (TERMINAL_RECORD (token->terminal))
1322 if (push_argument(argc, argv, word))
1323 return MATCHER_EXCEED_ARGC_MAX;
1326 cmd_matcher_record_match(matcher, word_match, token);
1328 matcher->word_index++;
1330 /* A vararg token should consume all left over words as arguments */
1331 if (token->terminal == TERMINAL_VARARG)
1332 while (cmd_matcher_words_left(matcher))
1334 word = cmd_matcher_get_word(matcher);
1335 if (word && strlen(word))
1336 push_argument(argc, argv, word);
1337 matcher->word_index++;
1343 static enum matcher_rv
1344 cmd_matcher_match_multiple(struct cmd_matcher *matcher,
1345 struct cmd_token *token,
1346 int *argc, const char **argv)
1348 enum match_type multiple_match;
1349 unsigned int multiple_index;
1351 const char *arg = NULL;
1352 struct cmd_token *word_token;
1353 enum match_type word_match;
1355 assert(token->type == TOKEN_MULTIPLE);
1357 multiple_match = no_match;
1359 if (!cmd_matcher_words_left(matcher))
1360 return MATCHER_INCOMPLETE;
1362 word = cmd_matcher_get_word(matcher);
1363 for (multiple_index = 0;
1364 multiple_index < vector_active(token->multiple);
1367 word_token = vector_slot(token->multiple, multiple_index);
1369 word_match = cmd_word_match(word_token, matcher->filter, word);
1370 if (word_match == no_match)
1373 cmd_matcher_record_match(matcher, word_match, word_token);
1375 if (word_match > multiple_match)
1377 multiple_match = word_match;
1380 /* To mimic the behavior of the old command implementation, we
1381 * tolerate any ambiguities here :/ */
1384 matcher->word_index++;
1386 if (multiple_match == no_match)
1387 return MATCHER_NO_MATCH;
1389 if (push_argument(argc, argv, arg))
1390 return MATCHER_EXCEED_ARGC_MAX;
1395 static enum matcher_rv
1396 cmd_matcher_read_keywords(struct cmd_matcher *matcher,
1397 struct cmd_token *token,
1401 unsigned long keyword_mask;
1402 unsigned int keyword_found;
1403 enum match_type keyword_match;
1404 enum match_type word_match;
1405 vector keyword_vector;
1406 struct cmd_token *word_token;
1409 const char **keyword_argv;
1410 enum matcher_rv rv = MATCHER_NO_MATCH;
1415 if (!cmd_matcher_words_left(matcher))
1418 word = cmd_matcher_get_word(matcher);
1421 keyword_match = no_match;
1422 for (i = 0; i < vector_active(token->keyword); i++)
1424 if (keyword_mask & (1 << i))
1427 keyword_vector = vector_slot(token->keyword, i);
1428 word_token = vector_slot(keyword_vector, 0);
1430 word_match = cmd_word_match(word_token, matcher->filter, word);
1431 if (word_match == no_match)
1434 cmd_matcher_record_match(matcher, word_match, word_token);
1436 if (word_match > keyword_match)
1438 keyword_match = word_match;
1441 else if (word_match == keyword_match)
1443 if (matcher->word_index != matcher->index || args_vector)
1444 return MATCHER_AMBIGUOUS;
1448 if (keyword_found == (unsigned int)-1)
1449 return MATCHER_NO_MATCH;
1451 matcher->word_index++;
1453 if (matcher->word_index > matcher->index)
1456 keyword_mask |= (1 << keyword_found);
1461 keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
1462 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1463 for (i = 0; i < CMD_ARGC_MAX + 1; i++)
1464 keyword_argv[i] = (void*)-1;
1465 vector_set_index(args_vector, keyword_found, keyword_argv);
1469 keyword_argv = NULL;
1472 keyword_vector = vector_slot(token->keyword, keyword_found);
1473 /* the keyword itself is at 0. We are only interested in the arguments,
1474 * so start counting at 1. */
1475 for (i = 1; i < vector_active(keyword_vector); i++)
1477 word_token = vector_slot(keyword_vector, i);
1479 switch (word_token->type)
1481 case TOKEN_TERMINAL:
1482 rv = cmd_matcher_match_terminal(matcher, word_token,
1483 &keyword_argc, keyword_argv);
1485 case TOKEN_MULTIPLE:
1486 rv = cmd_matcher_match_multiple(matcher, word_token,
1487 &keyword_argc, keyword_argv);
1490 assert(!"Keywords should never be nested.");
1494 if (MATCHER_ERROR(rv))
1497 if (matcher->word_index > matcher->index)
1504 static enum matcher_rv
1505 cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
1506 struct cmd_token *token,
1507 int *argc, const char **argv,
1508 vector keyword_args_vector)
1511 const char **keyword_args;
1512 vector keyword_vector;
1513 struct cmd_token *word_token;
1519 if (keyword_args_vector == NULL)
1522 for (i = 0; i < vector_active(token->keyword); i++)
1524 keyword_vector = vector_slot(token->keyword, i);
1525 keyword_args = vector_lookup(keyword_args_vector, i);
1527 if (vector_active(keyword_vector) == 1)
1529 /* this is a keyword without arguments */
1532 word_token = vector_slot(keyword_vector, 0);
1533 arg = word_token->cmd;
1540 if (push_argument(argc, argv, arg))
1541 rv = MATCHER_EXCEED_ARGC_MAX;
1545 /* this is a keyword with arguments */
1548 /* the keyword was present, so just fill in the arguments */
1549 for (j = 0; keyword_args[j] != (void*)-1; j++)
1550 if (push_argument(argc, argv, keyword_args[j]))
1551 rv = MATCHER_EXCEED_ARGC_MAX;
1552 XFREE(MTYPE_TMP, keyword_args);
1556 /* the keyword was not present, insert NULL for the arguments
1557 * the keyword would have taken. */
1558 for (j = 1; j < vector_active(keyword_vector); j++)
1560 word_token = vector_slot(keyword_vector, j);
1561 if ((word_token->type == TOKEN_TERMINAL
1562 && TERMINAL_RECORD (word_token->terminal))
1563 || word_token->type == TOKEN_MULTIPLE)
1565 if (push_argument(argc, argv, NULL))
1566 rv = MATCHER_EXCEED_ARGC_MAX;
1572 vector_free(keyword_args_vector);
1576 static enum matcher_rv
1577 cmd_matcher_match_keyword(struct cmd_matcher *matcher,
1578 struct cmd_token *token,
1579 int *argc, const char **argv)
1581 vector keyword_args_vector;
1582 enum matcher_rv reader_rv;
1583 enum matcher_rv builder_rv;
1585 assert(token->type == TOKEN_KEYWORD);
1588 keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
1590 keyword_args_vector = NULL;
1592 reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
1593 builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
1594 argv, keyword_args_vector);
1595 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1597 if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
1604 cmd_matcher_init(struct cmd_matcher *matcher,
1605 struct cmd_element *cmd,
1606 enum filter_type filter,
1609 enum match_type *match_type,
1612 memset(matcher, 0, sizeof(*matcher));
1615 matcher->filter = filter;
1616 matcher->vline = vline;
1617 matcher->index = index;
1619 matcher->match_type = match_type;
1620 if (matcher->match_type)
1621 *matcher->match_type = no_match;
1622 matcher->match = match;
1624 matcher->word_index = 0;
1627 static enum matcher_rv
1628 cmd_element_match(struct cmd_element *cmd_element,
1629 enum filter_type filter,
1632 enum match_type *match_type,
1637 struct cmd_matcher matcher;
1638 unsigned int token_index;
1639 enum matcher_rv rv = MATCHER_NO_MATCH;
1641 cmd_matcher_init(&matcher, cmd_element, filter,
1642 vline, index, match_type, match);
1647 for (token_index = 0;
1648 token_index < vector_active(cmd_element->tokens);
1651 struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
1653 switch (token->type)
1655 case TOKEN_TERMINAL:
1656 rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
1658 case TOKEN_MULTIPLE:
1659 rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
1662 rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
1665 if (MATCHER_ERROR(rv))
1668 if (matcher.word_index > index)
1672 /* return MATCHER_COMPLETE if all words were consumed */
1673 if (matcher.word_index >= vector_active(vline))
1674 return MATCHER_COMPLETE;
1676 /* return MATCHER_COMPLETE also if only an empty word is left. */
1677 if (matcher.word_index == vector_active(vline) - 1
1678 && (!vector_slot(vline, matcher.word_index)
1679 || !strlen((char*)vector_slot(vline, matcher.word_index))))
1680 return MATCHER_COMPLETE;
1682 return MATCHER_NO_MATCH; /* command is too long to match */
1686 * Filter a given vector of commands against a given commandline and
1687 * calculate possible completions.
1689 * @param commands A vector of struct cmd_element*. Commands that don't
1690 * match against the given command line will be overwritten
1691 * with NULL in that vector.
1692 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1693 * determines how incomplete commands are handled, compare with
1694 * cmd_word_match for details.
1695 * @param vline A vector of char* containing the tokenized commandline.
1696 * @param index Only match up to the given token of the commandline.
1697 * @param match_type Record the type of the best match here.
1698 * @param matches Record the matches here. For each cmd_element in the commands
1699 * vector, a match vector will be created in the matches vector.
1700 * That vector will contain all struct command_token* of the
1701 * cmd_element which matched against the given vline at the given
1703 * @return A code specifying if an error occurred. If all went right, it's
1707 cmd_vector_filter(vector commands,
1708 enum filter_type filter,
1711 enum match_type *match_type,
1715 struct cmd_element *cmd_element;
1716 enum match_type best_match;
1717 enum match_type element_match;
1718 enum matcher_rv matcher_rv;
1720 best_match = no_match;
1721 *matches = vector_init(VECTOR_MIN_SIZE);
1723 for (i = 0; i < vector_active (commands); i++)
1724 if ((cmd_element = vector_slot (commands, i)) != NULL)
1726 vector_set_index(*matches, i, NULL);
1727 matcher_rv = cmd_element_match(cmd_element, filter,
1730 (vector*)&vector_slot(*matches, i),
1732 if (MATCHER_ERROR(matcher_rv))
1734 vector_slot(commands, i) = NULL;
1735 if (matcher_rv == MATCHER_AMBIGUOUS)
1736 return CMD_ERR_AMBIGUOUS;
1737 if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
1738 return CMD_ERR_EXEED_ARGC_MAX;
1740 else if (element_match > best_match)
1742 best_match = element_match;
1745 *match_type = best_match;
1750 * Check whether a given commandline is complete if used for a specific
1753 * @param cmd_element A cmd_element against which the commandline should be
1755 * @param vline The tokenized commandline.
1756 * @return 1 if the given commandline is complete, 0 otherwise.
1759 cmd_is_complete(struct cmd_element *cmd_element,
1764 rv = cmd_element_match(cmd_element,
1769 return (rv == MATCHER_COMPLETE);
1773 * Parse a given commandline and construct a list of arguments for the
1774 * given command_element.
1776 * @param cmd_element The cmd_element for which we want to construct arguments.
1777 * @param vline The tokenized commandline.
1778 * @param argc Where to store the argument count.
1779 * @param argv Where to store the argument list. Should be at least
1780 * CMD_ARGC_MAX elements long.
1781 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1784 cmd_parse(struct cmd_element *cmd_element,
1786 int *argc, const char **argv)
1788 enum matcher_rv rv = cmd_element_match(cmd_element,
1795 case MATCHER_COMPLETE:
1798 case MATCHER_NO_MATCH:
1799 return CMD_ERR_NO_MATCH;
1801 case MATCHER_AMBIGUOUS:
1802 return CMD_ERR_AMBIGUOUS;
1804 case MATCHER_EXCEED_ARGC_MAX:
1805 return CMD_ERR_EXEED_ARGC_MAX;
1808 return CMD_ERR_INCOMPLETE;
1812 /* Check ambiguous match */
1814 is_cmd_ambiguous (vector cmd_vector,
1815 const char *command,
1817 enum match_type type)
1821 const char *str = NULL;
1822 const char *matched = NULL;
1823 vector match_vector;
1824 struct cmd_token *cmd_token;
1826 if (command == NULL)
1829 for (i = 0; i < vector_active (matches); i++)
1830 if ((match_vector = vector_slot (matches, i)) != NULL)
1834 for (j = 0; j < vector_active (match_vector); j++)
1835 if ((cmd_token = vector_slot (match_vector, j)) != NULL)
1837 enum match_type ret;
1839 assert(cmd_token->type == TOKEN_TERMINAL);
1840 if (cmd_token->type != TOKEN_TERMINAL)
1843 str = cmd_token->cmd;
1848 if (!TERMINAL_RECORD (cmd_token->terminal)
1849 && strcmp (command, str) == 0)
1853 if (!TERMINAL_RECORD (cmd_token->terminal)
1854 && strncmp (command, str, strlen (command)) == 0)
1856 if (matched && strcmp (matched, str) != 0)
1857 return 1; /* There is ambiguous match. */
1864 if (cmd_range_match (str, command))
1866 if (matched && strcmp (matched, str) != 0)
1875 if (cmd_token->terminal == TERMINAL_IPV6)
1878 case ipv6_prefix_match:
1879 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1881 if (ret == partly_match)
1882 return 2; /* There is incomplete match. */
1887 #endif /* HAVE_IPV6 */
1889 if (cmd_token->terminal == TERMINAL_IPV4)
1892 case ipv4_prefix_match:
1893 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1895 if (ret == partly_match)
1896 return 2; /* There is incomplete match. */
1902 if (TERMINAL_RECORD (cmd_token->terminal))
1911 vector_slot (cmd_vector, i) = NULL;
1916 /* If src matches dst return dst string, otherwise return NULL */
1918 cmd_entry_function (const char *src, struct cmd_token *token)
1920 const char *dst = token->cmd;
1922 /* Skip variable arguments. */
1923 if (TERMINAL_RECORD (token->terminal))
1926 /* In case of 'command \t', given src is NULL string. */
1930 /* Matched with input string. */
1931 if (strncmp (src, dst, strlen (src)) == 0)
1937 /* If src matches dst return dst string, otherwise return NULL */
1938 /* This version will return the dst string always if it is
1939 CMD_VARIABLE for '?' key processing */
1941 cmd_entry_function_desc (const char *src, struct cmd_token *token)
1943 const char *dst = token->cmd;
1945 switch (token->terminal)
1947 case TERMINAL_VARARG:
1950 case TERMINAL_RANGE:
1951 if (cmd_range_match (dst, src))
1957 if (cmd_ipv6_match (src))
1962 case TERMINAL_IPV6_PREFIX:
1963 if (cmd_ipv6_prefix_match (src))
1969 if (cmd_ipv4_match (src))
1974 case TERMINAL_IPV4_PREFIX:
1975 if (cmd_ipv4_prefix_match (src))
1980 /* Optional or variable commands always match on '?' */
1981 case TERMINAL_OPTION:
1982 case TERMINAL_VARIABLE:
1985 case TERMINAL_LITERAL:
1986 /* In case of 'command \t', given src is NULL string. */
1990 if (strncmp (src, dst, strlen (src)) == 0)
2002 * Check whether a string is already present in a vector of strings.
2003 * @param v A vector of char*.
2004 * @param str A char*.
2005 * @return 0 if str is already present in the vector, 1 otherwise.
2008 cmd_unique_string (vector v, const char *str)
2013 for (i = 0; i < vector_active (v); i++)
2014 if ((match = vector_slot (v, i)) != NULL)
2015 if (strcmp (match, str) == 0)
2021 * Check whether a struct cmd_token matching a given string is already
2022 * present in a vector of struct cmd_token.
2023 * @param v A vector of struct cmd_token*.
2024 * @param str A char* which should be searched for.
2025 * @return 0 if there is a struct cmd_token* with its cmd matching str,
2029 desc_unique_string (vector v, const char *str)
2032 struct cmd_token *token;
2034 for (i = 0; i < vector_active (v); i++)
2035 if ((token = vector_slot (v, i)) != NULL)
2036 if (strcmp (token->cmd, str) == 0)
2042 cmd_try_do_shortcut (enum node_type node, char* first_word) {
2043 if ( first_word != NULL &&
2044 node != AUTH_NODE &&
2045 node != VIEW_NODE &&
2046 node != AUTH_ENABLE_NODE &&
2047 node != ENABLE_NODE &&
2048 node != RESTRICTED_NODE &&
2049 0 == strcmp( "do", first_word ) )
2055 cmd_matches_free(vector *matches)
2060 for (i = 0; i < vector_active(*matches); i++)
2061 if ((cmd_matches = vector_slot(*matches, i)) != NULL)
2062 vector_free(cmd_matches);
2063 vector_free(*matches);
2068 cmd_describe_cmp(const void *a, const void *b)
2070 const struct cmd_token *first = *(struct cmd_token * const *)a;
2071 const struct cmd_token *second = *(struct cmd_token * const *)b;
2073 return strcmp(first->cmd, second->cmd);
2077 cmd_describe_sort(vector matchvec)
2079 qsort(matchvec->index, vector_active(matchvec),
2080 sizeof(void*), cmd_describe_cmp);
2083 /* '?' describe command support. */
2085 cmd_describe_command_real (vector vline, struct vty *vty, int *status)
2089 #define INIT_MATCHVEC_SIZE 10
2091 struct cmd_element *cmd_element;
2094 enum match_type match;
2096 vector matches = NULL;
2097 vector match_vector;
2098 uint32_t command_found = 0;
2099 const char *last_word;
2102 if (vector_active (vline) == 0)
2104 *status = CMD_ERR_NO_MATCH;
2108 index = vector_active (vline) - 1;
2110 /* Make copy vector of current node's command vector. */
2111 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2113 /* Prepare match vector */
2114 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2116 /* Filter commands and build a list how they could possibly continue. */
2117 for (i = 0; i <= index; i++)
2119 command = vector_slot (vline, i);
2122 cmd_matches_free(&matches);
2124 ret = cmd_vector_filter(cmd_vector,
2130 if (ret != CMD_SUCCESS)
2132 vector_free (cmd_vector);
2133 vector_free (matchvec);
2134 cmd_matches_free(&matches);
2139 /* The last match may well be ambigious, so break here */
2143 if (match == vararg_match)
2145 /* We found a vararg match - so we can throw out the current matches here
2146 * and don't need to continue checking the command input */
2149 for (j = 0; j < vector_active (matches); j++)
2150 if ((match_vector = vector_slot (matches, j)) != NULL)
2151 for (k = 0; k < vector_active (match_vector); k++)
2153 struct cmd_token *token = vector_slot (match_vector, k);
2154 vector_set (matchvec, token);
2157 *status = CMD_SUCCESS;
2158 vector_set(matchvec, &token_cr);
2159 vector_free (cmd_vector);
2160 cmd_matches_free(&matches);
2161 cmd_describe_sort(matchvec);
2165 ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
2168 vector_free (cmd_vector);
2169 vector_free (matchvec);
2170 cmd_matches_free(&matches);
2171 *status = CMD_ERR_AMBIGUOUS;
2176 vector_free (cmd_vector);
2177 vector_free (matchvec);
2178 cmd_matches_free(&matches);
2179 *status = CMD_ERR_NO_MATCH;
2184 /* Make description vector. */
2185 for (i = 0; i < vector_active (matches); i++)
2187 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
2190 vector vline_trimmed;
2193 last_word = vector_slot(vline, vector_active(vline) - 1);
2194 if (last_word == NULL || !strlen(last_word))
2196 vline_trimmed = vector_copy(vline);
2197 vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
2199 if (cmd_is_complete(cmd_element, vline_trimmed)
2200 && desc_unique_string(matchvec, command_cr))
2202 if (match != vararg_match)
2203 vector_set(matchvec, &token_cr);
2206 vector_free(vline_trimmed);
2209 match_vector = vector_slot (matches, i);
2212 for (j = 0; j < vector_active(match_vector); j++)
2214 struct cmd_token *token = vector_slot(match_vector, j);
2217 string = cmd_entry_function_desc(command, token);
2218 if (string && desc_unique_string(matchvec, string))
2219 vector_set(matchvec, token);
2226 * We can get into this situation when the command is complete
2227 * but the last part of the command is an optional piece of
2230 last_word = vector_slot(vline, vector_active(vline) - 1);
2231 if (command_found == 0 && (last_word == NULL || !strlen(last_word)))
2232 vector_set(matchvec, &token_cr);
2234 vector_free (cmd_vector);
2235 cmd_matches_free(&matches);
2237 if (vector_slot (matchvec, 0) == NULL)
2239 vector_free (matchvec);
2240 *status = CMD_ERR_NO_MATCH;
2244 *status = CMD_SUCCESS;
2245 cmd_describe_sort(matchvec);
2250 cmd_describe_command (vector vline, struct vty *vty, int *status)
2254 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2256 enum node_type onode;
2257 vector shifted_vline;
2261 vty->node = ENABLE_NODE;
2262 /* We can try it on enable node, cos' the vty is authenticated */
2264 shifted_vline = vector_init (vector_count(vline));
2266 for (index = 1; index < vector_active (vline); index++)
2268 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2271 ret = cmd_describe_command_real (shifted_vline, vty, status);
2273 vector_free(shifted_vline);
2279 return cmd_describe_command_real (vline, vty, status);
2283 /* Check LCD of matched command. */
2285 cmd_lcd (char **matched)
2293 if (matched[0] == NULL || matched[1] == NULL)
2296 for (i = 1; matched[i] != NULL; i++)
2298 s1 = matched[i - 1];
2301 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
2317 cmd_complete_cmp(const void *a, const void *b)
2319 const char *first = *(char * const *)a;
2320 const char *second = *(char * const *)b;
2331 return strcmp(first, second);
2335 cmd_complete_sort(vector matchvec)
2337 qsort(matchvec->index, vector_active(matchvec),
2338 sizeof(void*), cmd_complete_cmp);
2341 /* Command line completion support. */
2343 cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
2346 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2347 #define INIT_MATCHVEC_SIZE 10
2351 struct cmd_token *token;
2354 vector matches = NULL;
2355 vector match_vector;
2357 if (vector_active (vline) == 0)
2359 vector_free (cmd_vector);
2360 *status = CMD_ERR_NO_MATCH;
2364 index = vector_active (vline) - 1;
2366 /* First, filter by command string */
2367 for (i = 0; i <= index; i++)
2369 command = vector_slot (vline, i);
2370 enum match_type match;
2374 cmd_matches_free(&matches);
2376 /* First try completion match, if there is exactly match return 1 */
2377 ret = cmd_vector_filter(cmd_vector,
2383 if (ret != CMD_SUCCESS)
2385 vector_free(cmd_vector);
2386 cmd_matches_free(&matches);
2391 /* Break here - the completion mustn't be checked to be non-ambiguous */
2395 /* If there is exact match then filter ambiguous match else check
2397 ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2400 vector_free (cmd_vector);
2401 cmd_matches_free(&matches);
2402 *status = CMD_ERR_AMBIGUOUS;
2407 /* Prepare match vector. */
2408 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2410 /* Build the possible list of continuations into a list of completions */
2411 for (i = 0; i < vector_active (matches); i++)
2412 if ((match_vector = vector_slot (matches, i)))
2417 for (j = 0; j < vector_active (match_vector); j++)
2418 if ((token = vector_slot (match_vector, j)))
2420 string = cmd_entry_function (vector_slot (vline, index), token);
2421 if (string && cmd_unique_string (matchvec, string))
2422 vector_set (matchvec, (islib != 0 ?
2423 XSTRDUP (MTYPE_TMP, string) :
2424 strdup (string) /* rl freed */));
2428 /* We don't need cmd_vector any more. */
2429 vector_free (cmd_vector);
2430 cmd_matches_free(&matches);
2432 /* No matched command */
2433 if (vector_slot (matchvec, 0) == NULL)
2435 vector_free (matchvec);
2437 /* In case of 'command \t' pattern. Do you need '?' command at
2438 the end of the line. */
2439 if (vector_slot (vline, index) == '\0')
2440 *status = CMD_ERR_NOTHING_TODO;
2442 *status = CMD_ERR_NO_MATCH;
2446 /* Only one matched */
2447 if (vector_slot (matchvec, 1) == NULL)
2449 match_str = (char **) matchvec->index;
2450 vector_only_wrapper_free (matchvec);
2451 *status = CMD_COMPLETE_FULL_MATCH;
2454 /* Make it sure last element is NULL. */
2455 vector_set (matchvec, NULL);
2457 /* Check LCD of matched strings. */
2458 if (vector_slot (vline, index) != NULL)
2460 lcd = cmd_lcd ((char **) matchvec->index);
2464 int len = strlen (vector_slot (vline, index));
2470 lcdstr = (islib != 0 ?
2471 XMALLOC (MTYPE_TMP, lcd + 1) :
2473 memcpy (lcdstr, matchvec->index[0], lcd);
2476 /* Free matchvec. */
2477 for (i = 0; i < vector_active (matchvec); i++)
2479 if (vector_slot (matchvec, i))
2482 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
2484 free (vector_slot (matchvec, i));
2487 vector_free (matchvec);
2489 /* Make new matchvec. */
2490 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2491 vector_set (matchvec, lcdstr);
2492 match_str = (char **) matchvec->index;
2493 vector_only_wrapper_free (matchvec);
2495 *status = CMD_COMPLETE_MATCH;
2501 match_str = (char **) matchvec->index;
2502 cmd_complete_sort(matchvec);
2503 vector_only_wrapper_free (matchvec);
2504 *status = CMD_COMPLETE_LIST_MATCH;
2509 cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
2513 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2515 enum node_type onode;
2516 vector shifted_vline;
2520 vty->node = ENABLE_NODE;
2521 /* We can try it on enable node, cos' the vty is authenticated */
2523 shifted_vline = vector_init (vector_count(vline));
2525 for (index = 1; index < vector_active (vline); index++)
2527 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2530 ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
2532 vector_free(shifted_vline);
2537 return cmd_complete_command_real (vline, vty, status, islib);
2541 cmd_complete_command (vector vline, struct vty *vty, int *status)
2543 return cmd_complete_command_lib (vline, vty, status, 0);
2546 /* return parent node */
2547 /* MUST eventually converge on CONFIG_NODE */
2549 node_parent ( enum node_type node )
2553 assert (node > CONFIG_NODE);
2557 case BGP_VPNV4_NODE:
2558 case BGP_VPNV6_NODE:
2559 case BGP_ENCAP_NODE:
2560 case BGP_ENCAPV6_NODE:
2562 case BGP_IPV4M_NODE:
2564 case BGP_IPV6M_NODE:
2567 case KEYCHAIN_KEY_NODE:
2568 ret = KEYCHAIN_NODE;
2570 case LINK_PARAMS_NODE:
2571 ret = INTERFACE_NODE;
2581 /* Execute command by argument vline vector. */
2583 cmd_execute_command_real (vector vline,
2584 enum filter_type filter,
2586 struct cmd_element **cmd)
2591 struct cmd_element *cmd_element;
2592 struct cmd_element *matched_element;
2593 unsigned int matched_count, incomplete_count;
2595 const char *argv[CMD_ARGC_MAX];
2596 enum match_type match = 0;
2601 /* Make copy of command elements. */
2602 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2604 for (index = 0; index < vector_active (vline); index++)
2606 command = vector_slot (vline, index);
2607 ret = cmd_vector_filter(cmd_vector,
2613 if (ret != CMD_SUCCESS)
2615 cmd_matches_free(&matches);
2619 if (match == vararg_match)
2621 cmd_matches_free(&matches);
2625 ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2626 cmd_matches_free(&matches);
2630 vector_free(cmd_vector);
2631 return CMD_ERR_AMBIGUOUS;
2635 vector_free(cmd_vector);
2636 return CMD_ERR_NO_MATCH;
2640 /* Check matched count. */
2641 matched_element = NULL;
2643 incomplete_count = 0;
2645 for (i = 0; i < vector_active (cmd_vector); i++)
2646 if ((cmd_element = vector_slot (cmd_vector, i)))
2648 if (cmd_is_complete(cmd_element, vline))
2650 matched_element = cmd_element;
2659 /* Finish of using cmd_vector. */
2660 vector_free (cmd_vector);
2662 /* To execute command, matched_count must be 1. */
2663 if (matched_count == 0)
2665 if (incomplete_count)
2666 return CMD_ERR_INCOMPLETE;
2668 return CMD_ERR_NO_MATCH;
2671 if (matched_count > 1)
2672 return CMD_ERR_AMBIGUOUS;
2674 ret = cmd_parse(matched_element, vline, &argc, argv);
2675 if (ret != CMD_SUCCESS)
2678 /* For vtysh execution. */
2680 *cmd = matched_element;
2682 if (matched_element->daemon)
2683 return CMD_SUCCESS_DAEMON;
2685 /* Execute matched command. */
2686 return (*matched_element->func) (matched_element, vty, argc, argv);
2690 * Execute a given command, handling things like "do ..." and checking
2691 * whether the given command might apply at a parent node if doesn't
2692 * apply for the current node.
2694 * @param vline Command line input, vector of char* where each element is
2696 * @param vty The vty context in which the command should be executed.
2697 * @param cmd Pointer where the struct cmd_element of the matched command
2698 * will be stored, if any. May be set to NULL if this info is
2700 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2701 * @return The status of the command that has been executed or an error code
2702 * as to why no command could be executed.
2705 cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2707 int ret, saved_ret, tried = 0;
2708 enum node_type onode, try_node;
2710 onode = try_node = vty->node;
2712 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2714 vector shifted_vline;
2717 vty->node = ENABLE_NODE;
2718 /* We can try it on enable node, cos' the vty is authenticated */
2720 shifted_vline = vector_init (vector_count(vline));
2722 for (index = 1; index < vector_active (vline); index++)
2724 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2727 ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
2729 vector_free(shifted_vline);
2735 saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
2740 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2741 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
2742 && vty->node > CONFIG_NODE )
2744 try_node = node_parent(try_node);
2745 vty->node = try_node;
2746 ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
2748 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
2750 /* succesfull command, leave the node as is */
2754 /* no command succeeded, reset the vty to the original node and
2755 return the error for this node */
2762 * Execute a given command, matching it strictly against the current node.
2763 * This mode is used when reading config files.
2765 * @param vline Command line input, vector of char* where each element is
2767 * @param vty The vty context in which the command should be executed.
2768 * @param cmd Pointer where the struct cmd_element* of the matched command
2769 * will be stored, if any. May be set to NULL if this info is
2771 * @return The status of the command that has been executed or an error code
2772 * as to why no command could be executed.
2775 cmd_execute_command_strict (vector vline, struct vty *vty,
2776 struct cmd_element **cmd)
2778 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
2782 * Parse one line of config, walking up the parse tree attempting to find a match
2784 * @param vty The vty context in which the command should be executed.
2785 * @param cmd Pointer where the struct cmd_element* of the match command
2786 * will be stored, if any. May be set to NULL if this info is
2788 * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
2790 * @return The status of the command that has been executed or an error code
2791 * as to why no command could be executed.
2794 command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
2800 vline = cmd_make_strvec (vty->buf);
2802 /* In case of comment line */
2806 /* Execute configuration command : this is strict match */
2807 ret = cmd_execute_command_strict (vline, vty, cmd);
2809 saved_node = vty->node;
2811 while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
2812 ret != CMD_SUCCESS && ret != CMD_WARNING &&
2813 ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) {
2814 vty->node = node_parent(vty->node);
2815 ret = cmd_execute_command_strict (vline, vty, cmd);
2818 // If climbing the tree did not work then ignore the command and
2819 // stay at the same node
2820 if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
2821 ret != CMD_SUCCESS && ret != CMD_WARNING &&
2822 ret != CMD_ERR_NOTHING_TODO)
2824 vty->node = saved_node;
2827 cmd_free_strvec (vline);
2832 /* Configration make from file. */
2834 config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
2839 while (fgets (vty->buf, vty->max, fp))
2843 ret = command_config_read_one_line (vty, NULL, 0);
2845 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2846 && ret != CMD_ERR_NOTHING_TODO)
2852 /* Configration from terminal */
2853 DEFUN (config_terminal,
2854 config_terminal_cmd,
2855 "configure terminal",
2856 "Configuration from vty interface\n"
2857 "Configuration terminal\n")
2859 if (vty_config_lock (vty))
2860 vty->node = CONFIG_NODE;
2863 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2869 /* Enable command */
2873 "Turn on privileged mode command\n")
2875 /* If enable password is NULL, change to ENABLE_NODE */
2876 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2877 vty->type == VTY_SHELL_SERV)
2878 vty->node = ENABLE_NODE;
2880 vty->node = AUTH_ENABLE_NODE;
2885 /* Disable command */
2889 "Turn off privileged mode command\n")
2891 if (vty->node == ENABLE_NODE)
2892 vty->node = VIEW_NODE;
2896 /* Down vty node level. */
2900 "Exit current mode and down to previous mode\n")
2906 case RESTRICTED_NODE:
2907 if (vty_shell (vty))
2910 vty->status = VTY_CLOSE;
2913 vty->node = ENABLE_NODE;
2914 vty_config_unlock (vty);
2916 case INTERFACE_NODE:
2930 vty->node = CONFIG_NODE;
2933 case BGP_IPV4M_NODE:
2934 case BGP_VPNV4_NODE:
2935 case BGP_VPNV6_NODE:
2936 case BGP_ENCAP_NODE:
2937 case BGP_ENCAPV6_NODE:
2939 case BGP_IPV6M_NODE:
2940 vty->node = BGP_NODE;
2942 case KEYCHAIN_KEY_NODE:
2943 vty->node = KEYCHAIN_NODE;
2945 case LINK_PARAMS_NODE:
2946 vty->node = INTERFACE_NODE;
2954 /* quit is alias of exit. */
2958 "Exit current mode and down to previous mode\n")
2960 /* End of configuration. */
2964 "End current mode and change to enable mode.")
2970 case RESTRICTED_NODE:
2971 /* Nothing to do. */
2974 case INTERFACE_NODE:
2980 case BGP_ENCAP_NODE:
2981 case BGP_ENCAPV6_NODE:
2982 case BGP_VPNV4_NODE:
2983 case BGP_VPNV6_NODE:
2985 case BGP_IPV4M_NODE:
2987 case BGP_IPV6M_NODE:
2993 case KEYCHAIN_KEY_NODE:
2997 case LINK_PARAMS_NODE:
2998 vty_config_unlock (vty);
2999 vty->node = ENABLE_NODE;
3008 DEFUN (show_version,
3012 "Displays zebra version\n")
3014 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
3016 vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
3017 vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE,
3018 QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
3023 /* Help display function for all node. */
3027 "Description of the interactive help system\n")
3030 "Quagga VTY provides advanced help feature. When you need help,%s\
3031 anytime at the command line please press '?'.%s\
3033 If nothing matches, the help list will be empty and you must backup%s\
3034 until entering a '?' shows the available options.%s\
3035 Two styles of help are provided:%s\
3036 1. Full help is available when you are ready to enter a%s\
3037 command argument (e.g. 'show ?') and describes each possible%s\
3039 2. Partial help is provided when an abbreviated argument is entered%s\
3040 and you want to know what arguments match the input%s\
3041 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3042 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3043 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
3047 /* Help display function for all node. */
3051 "Print command list\n")
3054 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
3055 struct cmd_element *cmd;
3057 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
3058 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
3059 && !(cmd->attr == CMD_ATTR_DEPRECATED
3060 || cmd->attr == CMD_ATTR_HIDDEN))
3061 vty_out (vty, " %s%s", cmd->string,
3066 /* Write current configuration into file. */
3067 DEFUN (config_write_file,
3068 config_write_file_cmd,
3070 "Write running configuration to memory, network, or terminal\n"
3071 "Write to configuration file\n")
3075 struct cmd_node *node;
3077 char *config_file_tmp = NULL;
3078 char *config_file_sav = NULL;
3079 int ret = CMD_WARNING;
3080 struct vty *file_vty;
3082 /* Check and see if we are operating under vtysh configuration */
3083 if (host.config == NULL)
3085 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
3091 config_file = host.config;
3094 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
3095 strcpy (config_file_sav, config_file);
3096 strcat (config_file_sav, CONF_BACKUP_EXT);
3099 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
3100 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
3102 /* Open file to configuration write. */
3103 fd = mkstemp (config_file_tmp);
3106 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
3111 /* Make vty for configuration file. */
3112 file_vty = vty_new ();
3114 file_vty->type = VTY_FILE;
3116 /* Config file header print. */
3117 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
3118 vty_time_print (file_vty, 1);
3119 vty_out (file_vty, "!\n");
3121 for (i = 0; i < vector_active (cmdvec); i++)
3122 if ((node = vector_slot (cmdvec, i)) && node->func)
3124 if ((*node->func) (file_vty))
3125 vty_out (file_vty, "!\n");
3128 if ((dupfd = dup (file_vty->wfd)) < 0)
3130 vty_out (vty, "Couldn't dup fd (for fdatasync) for %s, %s (%d).%s",
3131 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3134 vty_close (file_vty);
3136 if (fdatasync (dupfd) < 0)
3138 vty_out (vty, "Couldn't fdatasync %s, %s (%d)!%s",
3139 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3142 if (unlink (config_file_sav) != 0)
3143 if (errno != ENOENT)
3145 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
3149 if (link (config_file, config_file_sav) != 0)
3151 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
3155 if (rename (config_file_tmp, config_file) != 0)
3157 vty_out (vty, "Can't move configuration file %s into place.%s",
3158 config_file, VTY_NEWLINE);
3161 if (chmod (config_file, CONFIGFILE_MASK) != 0)
3163 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
3164 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3168 vty_out (vty, "Configuration saved to %s%s", config_file,
3175 unlink (config_file_tmp);
3176 XFREE (MTYPE_TMP, config_file_tmp);
3177 XFREE (MTYPE_TMP, config_file_sav);
3181 ALIAS (config_write_file,
3184 "Write running configuration to memory, network, or terminal\n")
3186 ALIAS (config_write_file,
3187 config_write_memory_cmd,
3189 "Write running configuration to memory, network, or terminal\n"
3190 "Write configuration to the file (same as write file)\n")
3192 ALIAS (config_write_file,
3193 copy_runningconfig_startupconfig_cmd,
3194 "copy running-config startup-config",
3195 "Copy configuration\n"
3196 "Copy running config to... \n"
3197 "Copy running config to startup config (same as write file)\n")
3199 /* Write current configuration into the terminal. */
3200 DEFUN (config_write_terminal,
3201 config_write_terminal_cmd,
3203 "Write running configuration to memory, network, or terminal\n"
3204 "Write to terminal\n")
3207 struct cmd_node *node;
3209 if (vty->type == VTY_SHELL_SERV)
3211 for (i = 0; i < vector_active (cmdvec); i++)
3212 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
3214 if ((*node->func) (vty))
3215 vty_out (vty, "!%s", VTY_NEWLINE);
3220 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
3222 vty_out (vty, "!%s", VTY_NEWLINE);
3224 for (i = 0; i < vector_active (cmdvec); i++)
3225 if ((node = vector_slot (cmdvec, i)) && node->func)
3227 if ((*node->func) (vty))
3228 vty_out (vty, "!%s", VTY_NEWLINE);
3230 vty_out (vty, "end%s",VTY_NEWLINE);
3235 /* Write current configuration into the terminal. */
3236 ALIAS (config_write_terminal,
3237 show_running_config_cmd,
3238 "show running-config",
3240 "running configuration\n")
3242 /* Write startup configuration into the terminal. */
3243 DEFUN (show_startup_config,
3244 show_startup_config_cmd,
3245 "show startup-config",
3247 "Contentes of startup configuration\n")
3252 confp = fopen (host.config, "r");
3255 vty_out (vty, "Can't open configuration file [%s]%s",
3256 host.config, VTY_NEWLINE);
3260 while (fgets (buf, BUFSIZ, confp))
3264 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
3268 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
3276 /* Hostname configuration */
3277 DEFUN (config_hostname,
3280 "Set system's network name\n"
3281 "This system's network name\n")
3283 if (!isalpha((int) *argv[0]))
3285 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
3290 XFREE (MTYPE_HOST, host.name);
3292 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
3296 DEFUN (config_no_hostname,
3298 "no hostname [HOSTNAME]",
3300 "Reset system's network name\n"
3301 "Host name of this router\n")
3304 XFREE (MTYPE_HOST, host.name);
3309 /* VTY interface password set. */
3310 DEFUN (config_password, password_cmd,
3311 "password (8|) WORD",
3312 "Assign the terminal connection password\n"
3313 "Specifies a HIDDEN password will follow\n"
3315 "The HIDDEN line password string\n")
3317 /* Argument check. */
3320 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3326 if (*argv[0] == '8')
3329 XFREE (MTYPE_HOST, host.password);
3330 host.password = NULL;
3331 if (host.password_encrypt)
3332 XFREE (MTYPE_HOST, host.password_encrypt);
3333 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3338 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3343 if (!isalnum ((int) *argv[0]))
3346 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3351 XFREE (MTYPE_HOST, host.password);
3352 host.password = NULL;
3356 if (host.password_encrypt)
3357 XFREE (MTYPE_HOST, host.password_encrypt);
3358 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3361 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
3366 ALIAS (config_password, password_text_cmd,
3368 "Assign the terminal connection password\n"
3369 "The UNENCRYPTED (cleartext) line password\n")
3371 /* VTY enable password set. */
3372 DEFUN (config_enable_password, enable_password_cmd,
3373 "enable password (8|) WORD",
3374 "Modify enable password parameters\n"
3375 "Assign the privileged level password\n"
3376 "Specifies a HIDDEN password will follow\n"
3378 "The HIDDEN 'enable' password string\n")
3380 /* Argument check. */
3383 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3387 /* Crypt type is specified. */
3390 if (*argv[0] == '8')
3393 XFREE (MTYPE_HOST, host.enable);
3396 if (host.enable_encrypt)
3397 XFREE (MTYPE_HOST, host.enable_encrypt);
3398 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3404 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3409 if (!isalnum ((int) *argv[0]))
3412 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3417 XFREE (MTYPE_HOST, host.enable);
3420 /* Plain password input. */
3423 if (host.enable_encrypt)
3424 XFREE (MTYPE_HOST, host.enable_encrypt);
3425 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3428 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
3433 ALIAS (config_enable_password,
3434 enable_password_text_cmd,
3435 "enable password LINE",
3436 "Modify enable password parameters\n"
3437 "Assign the privileged level password\n"
3438 "The UNENCRYPTED (cleartext) 'enable' password\n")
3440 /* VTY enable password delete. */
3441 DEFUN (no_config_enable_password, no_enable_password_cmd,
3442 "no enable password",
3444 "Modify enable password parameters\n"
3445 "Assign the privileged level password\n")
3448 XFREE (MTYPE_HOST, host.enable);
3451 if (host.enable_encrypt)
3452 XFREE (MTYPE_HOST, host.enable_encrypt);
3453 host.enable_encrypt = NULL;
3458 DEFUN (service_password_encrypt,
3459 service_password_encrypt_cmd,
3460 "service password-encryption",
3461 "Set up miscellaneous service\n"
3462 "Enable encrypted passwords\n")
3471 if (host.password_encrypt)
3472 XFREE (MTYPE_HOST, host.password_encrypt);
3473 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
3477 if (host.enable_encrypt)
3478 XFREE (MTYPE_HOST, host.enable_encrypt);
3479 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
3485 DEFUN (no_service_password_encrypt,
3486 no_service_password_encrypt_cmd,
3487 "no service password-encryption",
3489 "Set up miscellaneous service\n"
3490 "Enable encrypted passwords\n")
3497 if (host.password_encrypt)
3498 XFREE (MTYPE_HOST, host.password_encrypt);
3499 host.password_encrypt = NULL;
3501 if (host.enable_encrypt)
3502 XFREE (MTYPE_HOST, host.enable_encrypt);
3503 host.enable_encrypt = NULL;
3508 DEFUN (config_terminal_length, config_terminal_length_cmd,
3509 "terminal length <0-512>",
3510 "Set terminal line parameters\n"
3511 "Set number of lines on a screen\n"
3512 "Number of lines on screen (0 for no pausing)\n")
3515 char *endptr = NULL;
3517 lines = strtol (argv[0], &endptr, 10);
3518 if (lines < 0 || lines > 512 || *endptr != '\0')
3520 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3528 DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
3529 "terminal no length",
3530 "Set terminal line parameters\n"
3532 "Set number of lines on a screen\n")
3538 DEFUN (service_terminal_length, service_terminal_length_cmd,
3539 "service terminal-length <0-512>",
3540 "Set up miscellaneous service\n"
3541 "System wide terminal length configuration\n"
3542 "Number of lines of VTY (0 means no line control)\n")
3545 char *endptr = NULL;
3547 lines = strtol (argv[0], &endptr, 10);
3548 if (lines < 0 || lines > 512 || *endptr != '\0')
3550 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3558 DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3559 "no service terminal-length [<0-512>]",
3561 "Set up miscellaneous service\n"
3562 "System wide terminal length configuration\n"
3563 "Number of lines of VTY (0 means no line control)\n")
3569 DEFUN_HIDDEN (do_echo,
3572 "Echo a message back to the vty\n"
3573 "The message to echo\n")
3577 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3580 XFREE(MTYPE_TMP, message);
3584 DEFUN (config_logmsg,
3586 "logmsg "LOG_LEVELS" .MESSAGE",
3587 "Send a message to enabled logging destinations\n"
3589 "The message to send\n")
3594 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3595 return CMD_ERR_NO_MATCH;
3597 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
3599 XFREE(MTYPE_TMP, message);
3603 DEFUN (show_logging,
3607 "Show current logging configuration\n")
3609 struct zlog *zl = zlog_default;
3611 vty_out (vty, "Syslog logging: ");
3612 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3613 vty_out (vty, "disabled");
3615 vty_out (vty, "level %s, facility %s, ident %s",
3616 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3617 facility_name(zl->facility), zl->ident);
3618 vty_out (vty, "%s", VTY_NEWLINE);
3620 vty_out (vty, "Stdout logging: ");
3621 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3622 vty_out (vty, "disabled");
3624 vty_out (vty, "level %s",
3625 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3626 vty_out (vty, "%s", VTY_NEWLINE);
3628 vty_out (vty, "Monitor logging: ");
3629 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3630 vty_out (vty, "disabled");
3632 vty_out (vty, "level %s",
3633 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3634 vty_out (vty, "%s", VTY_NEWLINE);
3636 vty_out (vty, "File logging: ");
3637 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3639 vty_out (vty, "disabled");
3641 vty_out (vty, "level %s, filename %s",
3642 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3644 vty_out (vty, "%s", VTY_NEWLINE);
3646 vty_out (vty, "Protocol name: %s%s",
3647 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3648 vty_out (vty, "Record priority: %s%s",
3649 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3650 vty_out (vty, "Timestamp precision: %d%s",
3651 zl->timestamp_precision, VTY_NEWLINE);
3656 DEFUN (config_log_stdout,
3657 config_log_stdout_cmd,
3660 "Set stdout logging level\n")
3662 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3666 DEFUN (config_log_stdout_level,
3667 config_log_stdout_level_cmd,
3668 "log stdout "LOG_LEVELS,
3670 "Set stdout logging level\n"
3675 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3676 return CMD_ERR_NO_MATCH;
3677 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3681 DEFUN (no_config_log_stdout,
3682 no_config_log_stdout_cmd,
3683 "no log stdout [LEVEL]",
3686 "Cancel logging to stdout\n"
3689 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3693 DEFUN (config_log_monitor,
3694 config_log_monitor_cmd,
3697 "Set terminal line (monitor) logging level\n")
3699 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3703 DEFUN (config_log_monitor_level,
3704 config_log_monitor_level_cmd,
3705 "log monitor "LOG_LEVELS,
3707 "Set terminal line (monitor) logging level\n"
3712 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3713 return CMD_ERR_NO_MATCH;
3714 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3718 DEFUN (no_config_log_monitor,
3719 no_config_log_monitor_cmd,
3720 "no log monitor [LEVEL]",
3723 "Disable terminal line (monitor) logging\n"
3726 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3731 set_log_file(struct vty *vty, const char *fname, int loglevel)
3735 const char *fullpath;
3737 /* Path detection. */
3738 if (! IS_DIRECTORY_SEP (*fname))
3740 char cwd[MAXPATHLEN+1];
3741 cwd[MAXPATHLEN] = '\0';
3743 if (getcwd (cwd, MAXPATHLEN) == NULL)
3745 zlog_err ("config_log_file: Unable to alloc mem!");
3749 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3752 zlog_err ("config_log_file: Unable to alloc mem!");
3755 sprintf (p, "%s/%s", cwd, fname);
3761 ret = zlog_set_file (NULL, fullpath, loglevel);
3764 XFREE (MTYPE_TMP, p);
3768 vty_out (vty, "can't open logfile %s\n", fname);
3773 XFREE (MTYPE_HOST, host.logfile);
3775 host.logfile = XSTRDUP (MTYPE_HOST, fname);
3780 DEFUN (config_log_file,
3781 config_log_file_cmd,
3782 "log file FILENAME",
3785 "Logging filename\n")
3787 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3790 DEFUN (config_log_file_level,
3791 config_log_file_level_cmd,
3792 "log file FILENAME "LOG_LEVELS,
3795 "Logging filename\n"
3800 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3801 return CMD_ERR_NO_MATCH;
3802 return set_log_file(vty, argv[0], level);
3805 DEFUN (no_config_log_file,
3806 no_config_log_file_cmd,
3807 "no log file [FILENAME]",
3810 "Cancel logging to file\n"
3811 "Logging file name\n")
3813 zlog_reset_file (NULL);
3816 XFREE (MTYPE_HOST, host.logfile);
3818 host.logfile = NULL;
3823 ALIAS (no_config_log_file,
3824 no_config_log_file_level_cmd,
3825 "no log file FILENAME LEVEL",
3828 "Cancel logging to file\n"
3829 "Logging file name\n"
3832 DEFUN (config_log_syslog,
3833 config_log_syslog_cmd,
3836 "Set syslog logging level\n")
3838 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3842 DEFUN (config_log_syslog_level,
3843 config_log_syslog_level_cmd,
3844 "log syslog "LOG_LEVELS,
3846 "Set syslog logging level\n"
3851 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3852 return CMD_ERR_NO_MATCH;
3853 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3857 DEFUN_DEPRECATED (config_log_syslog_facility,
3858 config_log_syslog_facility_cmd,
3859 "log syslog facility "LOG_FACILITIES,
3861 "Logging goes to syslog\n"
3862 "(Deprecated) Facility parameter for syslog messages\n"
3867 if ((facility = facility_match(argv[0])) < 0)
3868 return CMD_ERR_NO_MATCH;
3870 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3871 zlog_default->facility = facility;
3875 DEFUN (no_config_log_syslog,
3876 no_config_log_syslog_cmd,
3877 "no log syslog [LEVEL]",
3880 "Cancel logging to syslog\n"
3883 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3887 ALIAS (no_config_log_syslog,
3888 no_config_log_syslog_facility_cmd,
3889 "no log syslog facility "LOG_FACILITIES,
3892 "Logging goes to syslog\n"
3893 "Facility parameter for syslog messages\n"
3896 DEFUN (config_log_facility,
3897 config_log_facility_cmd,
3898 "log facility "LOG_FACILITIES,
3900 "Facility parameter for syslog messages\n"
3905 if ((facility = facility_match(argv[0])) < 0)
3906 return CMD_ERR_NO_MATCH;
3907 zlog_default->facility = facility;
3911 DEFUN (no_config_log_facility,
3912 no_config_log_facility_cmd,
3913 "no log facility [FACILITY]",
3916 "Reset syslog facility to default (daemon)\n"
3917 "Syslog facility\n")
3919 zlog_default->facility = LOG_DAEMON;
3923 DEFUN_DEPRECATED (config_log_trap,
3924 config_log_trap_cmd,
3925 "log trap "LOG_LEVELS,
3927 "(Deprecated) Set logging level and default for all destinations\n"
3933 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3934 return CMD_ERR_NO_MATCH;
3936 zlog_default->default_lvl = new_level;
3937 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3938 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3939 zlog_default->maxlvl[i] = new_level;
3943 DEFUN_DEPRECATED (no_config_log_trap,
3944 no_config_log_trap_cmd,
3945 "no log trap [LEVEL]",
3948 "Permit all logging information\n"
3951 zlog_default->default_lvl = LOG_DEBUG;
3955 DEFUN (config_log_record_priority,
3956 config_log_record_priority_cmd,
3957 "log record-priority",
3959 "Log the priority of the message within the message\n")
3961 zlog_default->record_priority = 1 ;
3965 DEFUN (no_config_log_record_priority,
3966 no_config_log_record_priority_cmd,
3967 "no log record-priority",
3970 "Do not log the priority of the message within the message\n")
3972 zlog_default->record_priority = 0 ;
3976 DEFUN (config_log_timestamp_precision,
3977 config_log_timestamp_precision_cmd,
3978 "log timestamp precision <0-6>",
3980 "Timestamp configuration\n"
3981 "Set the timestamp precision\n"
3982 "Number of subsecond digits\n")
3986 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3990 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3991 zlog_default->timestamp_precision, argv[0], 0, 6);
3995 DEFUN (no_config_log_timestamp_precision,
3996 no_config_log_timestamp_precision_cmd,
3997 "no log timestamp precision",
4000 "Timestamp configuration\n"
4001 "Reset the timestamp precision to the default value of 0\n")
4003 zlog_default->timestamp_precision = 0 ;
4007 DEFUN (banner_motd_file,
4008 banner_motd_file_cmd,
4009 "banner motd file [FILE]",
4012 "Banner from a file\n"
4016 XFREE (MTYPE_HOST, host.motdfile);
4017 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
4022 DEFUN (banner_motd_default,
4023 banner_motd_default_cmd,
4024 "banner motd default",
4025 "Set banner string\n"
4026 "Strings for motd\n"
4029 host.motd = default_motd;
4033 DEFUN (no_banner_motd,
4037 "Set banner string\n"
4038 "Strings for motd\n")
4042 XFREE (MTYPE_HOST, host.motdfile);
4043 host.motdfile = NULL;
4047 DEFUN (show_commandtree,
4048 show_commandtree_cmd,
4051 "Show command tree\n")
4057 vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE);
4059 /* vector of all commands installed at this node */
4060 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
4062 /* loop over all commands at this node */
4063 for (i = 0; i < vector_active(cmd_vector); ++i)
4065 struct cmd_element *cmd_element;
4067 /* A cmd_element (seems to be) is an individual command */
4068 if ((cmd_element = vector_slot (cmd_vector, i)) == NULL)
4071 vty_out (vty, " %s%s", cmd_element->string, VTY_NEWLINE);
4074 vector_free (cmd_vector);
4078 /* Set config filename. Called from vty.c */
4080 host_config_set (char *filename)
4083 XFREE (MTYPE_HOST, host.config);
4084 host.config = XSTRDUP (MTYPE_HOST, filename);
4088 host_config_get (void)
4094 install_default_basic (enum node_type node)
4096 install_element (node, &config_exit_cmd);
4097 install_element (node, &config_quit_cmd);
4098 install_element (node, &config_help_cmd);
4099 install_element (node, &config_list_cmd);
4102 /* Install common/default commands for a privileged node */
4104 install_default (enum node_type node)
4106 /* VIEW_NODE is inited below, via install_default_basic, and
4107 install_element's of commands to VIEW_NODE automatically are
4108 also installed to ENABLE_NODE.
4110 For all other nodes, we must ensure install_default_basic is
4113 if (node != VIEW_NODE && node != ENABLE_NODE)
4114 install_default_basic (node);
4116 install_element (node, &config_end_cmd);
4117 install_element (node, &config_write_terminal_cmd);
4118 install_element (node, &config_write_file_cmd);
4119 install_element (node, &config_write_memory_cmd);
4120 install_element (node, &config_write_cmd);
4121 install_element (node, &show_running_config_cmd);
4124 /* Initialize command interface. Install basic nodes and commands. */
4126 cmd_init (int terminal)
4128 command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
4129 token_cr.type = TOKEN_TERMINAL;
4130 token_cr.terminal = TERMINAL_LITERAL;
4131 token_cr.cmd = command_cr;
4132 token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
4134 /* Allocate initial top vector of commands. */
4135 cmdvec = vector_init (VECTOR_MIN_SIZE);
4137 /* Default host value settings. */
4139 host.password = NULL;
4141 host.logfile = NULL;
4144 host.motd = default_motd;
4145 host.motdfile = NULL;
4147 /* Install top nodes. */
4148 install_node (&view_node, NULL);
4149 install_node (&enable_node, NULL);
4150 install_node (&auth_node, NULL);
4151 install_node (&auth_enable_node, NULL);
4152 install_node (&restricted_node, NULL);
4153 install_node (&config_node, config_write_host);
4155 /* Each node's basic commands. */
4156 install_element (VIEW_NODE, &show_version_cmd);
4159 install_default_basic (VIEW_NODE);
4161 install_element (VIEW_NODE, &config_enable_cmd);
4162 install_element (VIEW_NODE, &config_terminal_length_cmd);
4163 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
4164 install_element (VIEW_NODE, &show_logging_cmd);
4165 install_element (VIEW_NODE, &show_commandtree_cmd);
4166 install_element (VIEW_NODE, &echo_cmd);
4168 install_element (RESTRICTED_NODE, &config_enable_cmd);
4169 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
4170 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
4171 install_element (RESTRICTED_NODE, &show_commandtree_cmd);
4172 install_element (RESTRICTED_NODE, &echo_cmd);
4177 install_default (ENABLE_NODE);
4178 install_element (ENABLE_NODE, &config_disable_cmd);
4179 install_element (ENABLE_NODE, &config_terminal_cmd);
4180 install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd);
4182 install_element (ENABLE_NODE, &show_startup_config_cmd);
4186 install_element (ENABLE_NODE, &config_logmsg_cmd);
4188 install_default (CONFIG_NODE);
4191 install_element (CONFIG_NODE, &hostname_cmd);
4192 install_element (CONFIG_NODE, &no_hostname_cmd);
4196 install_element (CONFIG_NODE, &password_cmd);
4197 install_element (CONFIG_NODE, &password_text_cmd);
4198 install_element (CONFIG_NODE, &enable_password_cmd);
4199 install_element (CONFIG_NODE, &enable_password_text_cmd);
4200 install_element (CONFIG_NODE, &no_enable_password_cmd);
4202 install_element (CONFIG_NODE, &config_log_stdout_cmd);
4203 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
4204 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
4205 install_element (CONFIG_NODE, &config_log_monitor_cmd);
4206 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
4207 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
4208 install_element (CONFIG_NODE, &config_log_file_cmd);
4209 install_element (CONFIG_NODE, &config_log_file_level_cmd);
4210 install_element (CONFIG_NODE, &no_config_log_file_cmd);
4211 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
4212 install_element (CONFIG_NODE, &config_log_syslog_cmd);
4213 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
4214 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
4215 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
4216 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
4217 install_element (CONFIG_NODE, &config_log_facility_cmd);
4218 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
4219 install_element (CONFIG_NODE, &config_log_trap_cmd);
4220 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
4221 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
4222 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
4223 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
4224 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
4225 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
4226 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
4227 install_element (CONFIG_NODE, &banner_motd_default_cmd);
4228 install_element (CONFIG_NODE, &banner_motd_file_cmd);
4229 install_element (CONFIG_NODE, &no_banner_motd_cmd);
4230 install_element (CONFIG_NODE, &service_terminal_length_cmd);
4231 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
4233 install_element (VIEW_NODE, &show_thread_cpu_cmd);
4234 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
4236 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
4237 install_element (VIEW_NODE, &show_work_queues_cmd);
4239 install_element (CONFIG_NODE, &show_commandtree_cmd);
4240 srandom(time(NULL));
4244 cmd_terminate_token(struct cmd_token *token)
4247 vector keyword_vect;
4249 if (token->multiple)
4251 for (i = 0; i < vector_active(token->multiple); i++)
4252 cmd_terminate_token(vector_slot(token->multiple, i));
4253 vector_free(token->multiple);
4254 token->multiple = NULL;
4259 for (i = 0; i < vector_active(token->keyword); i++)
4261 keyword_vect = vector_slot(token->keyword, i);
4262 for (j = 0; j < vector_active(keyword_vect); j++)
4263 cmd_terminate_token(vector_slot(keyword_vect, j));
4264 vector_free(keyword_vect);
4266 vector_free(token->keyword);
4267 token->keyword = NULL;
4270 XFREE(MTYPE_CMD_TOKENS, token->cmd);
4271 XFREE(MTYPE_CMD_TOKENS, token->desc);
4273 XFREE(MTYPE_CMD_TOKENS, token);
4277 cmd_terminate_element(struct cmd_element *cmd)
4281 if (cmd->tokens == NULL)
4284 for (i = 0; i < vector_active(cmd->tokens); i++)
4285 cmd_terminate_token(vector_slot(cmd->tokens, i));
4287 vector_free(cmd->tokens);
4295 struct cmd_node *cmd_node;
4296 struct cmd_element *cmd_element;
4301 for (i = 0; i < vector_active (cmdvec); i++)
4302 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
4304 cmd_node_v = cmd_node->cmd_vector;
4306 for (j = 0; j < vector_active (cmd_node_v); j++)
4307 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
4308 cmd_terminate_element(cmd_element);
4310 vector_free (cmd_node_v);
4311 hash_clean (cmd_node->cmd_hash, NULL);
4312 hash_free (cmd_node->cmd_hash);
4313 cmd_node->cmd_hash = NULL;
4316 vector_free (cmdvec);
4321 XFREE(MTYPE_CMD_TOKENS, command_cr);
4323 XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
4325 XFREE (MTYPE_HOST, host.name);
4327 XFREE (MTYPE_HOST, host.password);
4328 if (host.password_encrypt)
4329 XFREE (MTYPE_HOST, host.password_encrypt);
4331 XFREE (MTYPE_HOST, host.enable);
4332 if (host.enable_encrypt)
4333 XFREE (MTYPE_HOST, host.enable_encrypt);
4335 XFREE (MTYPE_HOST, host.logfile);
4337 XFREE (MTYPE_HOST, host.motdfile);
4339 XFREE (MTYPE_HOST, host.config);