Annotation of embedaddon/quagga/lib/command.c, revision 1.1.1.4
1.1 misho 1: /*
2: Command interpreter routine for virtual terminal [aka TeletYpe]
3: Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
1.1.1.4 ! misho 4: Copyright (C) 2013 by Open Source Routing.
! 5: Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
1.1 misho 6:
7: This file is part of GNU Zebra.
8:
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.
13:
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.
18:
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. */
23:
24: #include <zebra.h>
25:
26:
27: #include "memory.h"
28: #include "log.h"
29: #include <lib/version.h>
30: #include "thread.h"
31: #include "vector.h"
32: #include "vty.h"
33: #include "command.h"
34: #include "workqueue.h"
35:
36: /* Command vector which includes some level of command lists. Normally
37: each daemon maintains each own cmdvec. */
38: vector cmdvec = NULL;
39:
1.1.1.4 ! misho 40: struct cmd_token token_cr;
1.1 misho 41: char *command_cr = NULL;
42:
1.1.1.4 ! misho 43: enum filter_type
! 44: {
! 45: FILTER_RELAXED,
! 46: FILTER_STRICT
! 47: };
! 48:
! 49: enum matcher_rv
! 50: {
! 51: MATCHER_OK,
! 52: MATCHER_COMPLETE,
! 53: MATCHER_INCOMPLETE,
! 54: MATCHER_NO_MATCH,
! 55: MATCHER_AMBIGUOUS,
! 56: MATCHER_EXCEED_ARGC_MAX
! 57: };
! 58:
! 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 \
! 64: )
! 65:
1.1 misho 66: /* Host information structure. */
67: struct host host;
68:
69: /* Standard command node structures. */
70: static struct cmd_node auth_node =
71: {
72: AUTH_NODE,
73: "Password: ",
74: };
75:
76: static struct cmd_node view_node =
77: {
78: VIEW_NODE,
79: "%s> ",
80: };
81:
82: static struct cmd_node restricted_node =
83: {
84: RESTRICTED_NODE,
85: "%s$ ",
86: };
87:
88: static struct cmd_node auth_enable_node =
89: {
90: AUTH_ENABLE_NODE,
91: "Password: ",
92: };
93:
94: static struct cmd_node enable_node =
95: {
96: ENABLE_NODE,
97: "%s# ",
98: };
99:
100: static struct cmd_node config_node =
101: {
102: CONFIG_NODE,
103: "%s(config)# ",
104: 1
105: };
106:
107: /* Default motd string. */
108: static const char *default_motd =
109: "\r\n\
110: Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
111: " QUAGGA_COPYRIGHT "\r\n\
1.1.1.3 misho 112: " GIT_INFO "\r\n";
1.1 misho 113:
114:
115: static const struct facility_map {
116: int facility;
117: const char *name;
118: size_t match;
119: } syslog_facilities[] =
120: {
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 },
131: #ifdef LOG_FTP
132: { LOG_FTP, "ftp", 1 },
133: #endif
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 },
142: { 0, NULL, 0 },
143: };
144:
145: static const char *
146: facility_name(int facility)
147: {
148: const struct facility_map *fm;
149:
150: for (fm = syslog_facilities; fm->name; fm++)
151: if (fm->facility == facility)
152: return fm->name;
153: return "";
154: }
155:
156: static int
157: facility_match(const char *str)
158: {
159: const struct facility_map *fm;
160:
161: for (fm = syslog_facilities; fm->name; fm++)
162: if (!strncmp(str,fm->name,fm->match))
163: return fm->facility;
164: return -1;
165: }
166:
167: static int
168: level_match(const char *s)
169: {
170: int level ;
171:
172: for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
173: if (!strncmp (s, zlog_priority[level], 2))
174: return level;
175: return ZLOG_DISABLED;
176: }
177:
178: /* This is called from main when a daemon is invoked with -v or --version. */
179: void
180: print_version (const char *progname)
181: {
182: printf ("%s version %s\n", progname, QUAGGA_VERSION);
183: printf ("%s\n", QUAGGA_COPYRIGHT);
1.1.1.4 ! misho 184: printf ("configured with:\n\t%s\n", QUAGGA_CONFIG_ARGS);
1.1 misho 185: }
186:
1.1.1.4 ! misho 187:
1.1 misho 188: /* Utility function to concatenate argv argument into a single string
189: with inserting ' ' character between each argument. */
190: char *
191: argv_concat (const char **argv, int argc, int shift)
192: {
193: int i;
194: size_t len;
195: char *str;
196: char *p;
197:
198: len = 0;
199: for (i = shift; i < argc; i++)
200: len += strlen(argv[i])+1;
201: if (!len)
202: return NULL;
203: p = str = XMALLOC(MTYPE_TMP, len);
204: for (i = shift; i < argc; i++)
205: {
206: size_t arglen;
207: memcpy(p, argv[i], (arglen = strlen(argv[i])));
208: p += arglen;
209: *p++ = ' ';
210: }
211: *(p-1) = '\0';
212: return str;
213: }
214:
215: /* Install top node of command vector. */
216: void
217: install_node (struct cmd_node *node,
218: int (*func) (struct vty *))
219: {
220: vector_set_index (cmdvec, node->node, node);
221: node->func = func;
222: node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
223: }
224:
225: /* Breaking up string into each command piece. I assume given
226: character is separated by a space character. Return value is a
227: vector which includes char ** data element. */
228: vector
229: cmd_make_strvec (const char *string)
230: {
231: const char *cp, *start;
232: char *token;
233: int strlen;
234: vector strvec;
235:
236: if (string == NULL)
237: return NULL;
238:
239: cp = string;
240:
241: /* Skip white spaces. */
242: while (isspace ((int) *cp) && *cp != '\0')
243: cp++;
244:
245: /* Return if there is only white spaces */
246: if (*cp == '\0')
247: return NULL;
248:
249: if (*cp == '!' || *cp == '#')
250: return NULL;
251:
252: /* Prepare return vector. */
253: strvec = vector_init (VECTOR_MIN_SIZE);
254:
255: /* Copy each command piece and set into vector. */
256: while (1)
257: {
258: start = cp;
259: while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
260: *cp != '\0')
261: cp++;
262: strlen = cp - start;
263: token = XMALLOC (MTYPE_STRVEC, strlen + 1);
264: memcpy (token, start, strlen);
265: *(token + strlen) = '\0';
266: vector_set (strvec, token);
267:
268: while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
269: *cp != '\0')
270: cp++;
271:
272: if (*cp == '\0')
273: return strvec;
274: }
275: }
276:
277: /* Free allocated string vector. */
278: void
279: cmd_free_strvec (vector v)
280: {
281: unsigned int i;
282: char *cp;
283:
284: if (!v)
285: return;
286:
287: for (i = 0; i < vector_active (v); i++)
288: if ((cp = vector_slot (v, i)) != NULL)
289: XFREE (MTYPE_STRVEC, cp);
290:
291: vector_free (v);
292: }
293:
1.1.1.4 ! misho 294: struct format_parser_state
! 295: {
! 296: vector topvect; /* Top level vector */
! 297: vector intvect; /* Intermediate level vector, used when there's
! 298: * a multiple in a keyword. */
! 299: vector curvect; /* current vector where read tokens should be
! 300: appended. */
! 301:
! 302: const char *string; /* pointer to command string, not modified */
! 303: const char *cp; /* pointer in command string, moved along while
! 304: parsing */
! 305: const char *dp; /* pointer in description string, moved along while
! 306: parsing */
! 307:
! 308: int in_keyword; /* flag to remember if we are in a keyword group */
! 309: int in_multiple; /* flag to remember if we are in a multiple group */
! 310: int just_read_word; /* flag to remember if the last thing we red was a
! 311: * real word and not some abstract token */
! 312: };
! 313:
! 314: static void
! 315: format_parser_error(struct format_parser_state *state, const char *message)
! 316: {
! 317: int offset = state->cp - state->string + 1;
! 318:
! 319: fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
! 320: fprintf(stderr, " %*c\n", offset, '^');
! 321: fprintf(stderr, "%s at offset %d.\n", message, offset);
! 322: fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
! 323: exit(1);
! 324: }
! 325:
1.1 misho 326: static char *
1.1.1.4 ! misho 327: format_parser_desc_str(struct format_parser_state *state)
1.1 misho 328: {
329: const char *cp, *start;
330: char *token;
331: int strlen;
1.1.1.4 ! misho 332:
! 333: cp = state->dp;
1.1 misho 334:
335: if (cp == NULL)
336: return NULL;
337:
338: /* Skip white spaces. */
339: while (isspace ((int) *cp) && *cp != '\0')
340: cp++;
341:
342: /* Return if there is only white spaces */
343: if (*cp == '\0')
344: return NULL;
345:
346: start = cp;
347:
348: while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
349: cp++;
350:
351: strlen = cp - start;
1.1.1.4 ! misho 352: token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
1.1 misho 353: memcpy (token, start, strlen);
354: *(token + strlen) = '\0';
355:
1.1.1.4 ! misho 356: state->dp = cp;
1.1 misho 357:
358: return token;
359: }
360:
1.1.1.4 ! misho 361: static void
! 362: format_parser_begin_keyword(struct format_parser_state *state)
1.1 misho 363: {
1.1.1.4 ! misho 364: struct cmd_token *token;
! 365: vector keyword_vect;
1.1 misho 366:
1.1.1.4 ! misho 367: if (state->in_keyword
! 368: || state->in_multiple)
! 369: format_parser_error(state, "Unexpected '{'");
1.1 misho 370:
1.1.1.4 ! misho 371: state->cp++;
! 372: state->in_keyword = 1;
1.1 misho 373:
1.1.1.4 ! misho 374: token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
! 375: token->type = TOKEN_KEYWORD;
! 376: token->keyword = vector_init(VECTOR_MIN_SIZE);
1.1 misho 377:
1.1.1.4 ! misho 378: keyword_vect = vector_init(VECTOR_MIN_SIZE);
! 379: vector_set(token->keyword, keyword_vect);
1.1 misho 380:
1.1.1.4 ! misho 381: vector_set(state->curvect, token);
! 382: state->curvect = keyword_vect;
! 383: }
1.1 misho 384:
1.1.1.4 ! misho 385: static void
! 386: format_parser_begin_multiple(struct format_parser_state *state)
! 387: {
! 388: struct cmd_token *token;
1.1 misho 389:
1.1.1.4 ! misho 390: if (state->in_keyword == 1)
! 391: format_parser_error(state, "Keyword starting with '('");
1.1 misho 392:
1.1.1.4 ! misho 393: if (state->in_multiple)
! 394: format_parser_error(state, "Nested group");
1.1 misho 395:
1.1.1.4 ! misho 396: state->cp++;
! 397: state->in_multiple = 1;
! 398: state->just_read_word = 0;
1.1 misho 399:
1.1.1.4 ! misho 400: token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
! 401: token->type = TOKEN_MULTIPLE;
! 402: token->multiple = vector_init(VECTOR_MIN_SIZE);
1.1 misho 403:
1.1.1.4 ! misho 404: vector_set(state->curvect, token);
! 405: if (state->curvect != state->topvect)
! 406: state->intvect = state->curvect;
! 407: state->curvect = token->multiple;
! 408: }
1.1 misho 409:
1.1.1.4 ! misho 410: static void
! 411: format_parser_end_keyword(struct format_parser_state *state)
! 412: {
! 413: if (state->in_multiple
! 414: || !state->in_keyword)
! 415: format_parser_error(state, "Unexpected '}'");
! 416:
! 417: if (state->in_keyword == 1)
! 418: format_parser_error(state, "Empty keyword group");
! 419:
! 420: state->cp++;
! 421: state->in_keyword = 0;
! 422: state->curvect = state->topvect;
! 423: }
1.1 misho 424:
1.1.1.4 ! misho 425: static void
! 426: format_parser_end_multiple(struct format_parser_state *state)
! 427: {
! 428: char *dummy;
! 429:
! 430: if (!state->in_multiple)
! 431: format_parser_error(state, "Unepexted ')'");
! 432:
! 433: if (vector_active(state->curvect) == 0)
! 434: format_parser_error(state, "Empty multiple section");
! 435:
! 436: if (!state->just_read_word)
! 437: {
! 438: /* There are constructions like
! 439: * 'show ip ospf database ... (self-originate|)'
! 440: * in use.
! 441: * The old parser reads a description string for the
! 442: * word '' between |) which will never match.
! 443: * Simulate this behvaior by dropping the next desc
! 444: * string in such a case. */
! 445:
! 446: dummy = format_parser_desc_str(state);
! 447: XFREE(MTYPE_CMD_TOKENS, dummy);
1.1 misho 448: }
1.1.1.4 ! misho 449:
! 450: state->cp++;
! 451: state->in_multiple = 0;
! 452:
! 453: if (state->intvect)
! 454: state->curvect = state->intvect;
! 455: else
! 456: state->curvect = state->topvect;
1.1 misho 457: }
458:
1.1.1.4 ! misho 459: static void
! 460: format_parser_handle_pipe(struct format_parser_state *state)
1.1 misho 461: {
1.1.1.4 ! misho 462: struct cmd_token *keyword_token;
! 463: vector keyword_vect;
1.1 misho 464:
1.1.1.4 ! misho 465: if (state->in_multiple)
1.1 misho 466: {
1.1.1.4 ! misho 467: state->just_read_word = 0;
! 468: state->cp++;
! 469: }
! 470: else if (state->in_keyword)
! 471: {
! 472: state->in_keyword = 1;
! 473: state->cp++;
! 474:
! 475: keyword_token = vector_slot(state->topvect,
! 476: vector_active(state->topvect) - 1);
! 477: keyword_vect = vector_init(VECTOR_MIN_SIZE);
! 478: vector_set(keyword_token->keyword, keyword_vect);
! 479: state->curvect = keyword_vect;
! 480: }
! 481: else
! 482: {
! 483: format_parser_error(state, "Unexpected '|'");
! 484: }
! 485: }
! 486:
! 487: static void
! 488: format_parser_read_word(struct format_parser_state *state)
! 489: {
! 490: const char *start;
! 491: int len;
! 492: char *cmd;
! 493: struct cmd_token *token;
! 494:
! 495: start = state->cp;
! 496:
! 497: while (state->cp[0] != '\0'
! 498: && !strchr("\r\n(){}|", state->cp[0])
! 499: && !isspace((int)state->cp[0]))
! 500: state->cp++;
! 501:
! 502: len = state->cp - start;
! 503: cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
! 504: memcpy(cmd, start, len);
! 505: cmd[len] = '\0';
! 506:
! 507: token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
! 508: token->type = TOKEN_TERMINAL;
! 509: if (strcmp (cmd, "A.B.C.D") == 0)
! 510: token->terminal = TERMINAL_IPV4;
! 511: else if (strcmp (cmd, "A.B.C.D/M") == 0)
! 512: token->terminal = TERMINAL_IPV4_PREFIX;
! 513: else if (strcmp (cmd, "X:X::X:X") == 0)
! 514: token->terminal = TERMINAL_IPV6;
! 515: else if (strcmp (cmd, "X:X::X:X/M") == 0)
! 516: token->terminal = TERMINAL_IPV6_PREFIX;
! 517: else if (cmd[0] == '[')
! 518: token->terminal = TERMINAL_OPTION;
! 519: else if (cmd[0] == '.')
! 520: token->terminal = TERMINAL_VARARG;
! 521: else if (cmd[0] == '<')
! 522: token->terminal = TERMINAL_RANGE;
! 523: else if (cmd[0] >= 'A' && cmd[0] <= 'Z')
! 524: token->terminal = TERMINAL_VARIABLE;
! 525: else
! 526: token->terminal = TERMINAL_LITERAL;
! 527:
! 528: token->cmd = cmd;
! 529: token->desc = format_parser_desc_str(state);
! 530: vector_set(state->curvect, token);
! 531:
! 532: if (state->in_keyword == 1)
! 533: state->in_keyword = 2;
! 534:
! 535: state->just_read_word = 1;
! 536: }
! 537:
! 538: /**
! 539: * Parse a given command format string and build a tree of tokens from
! 540: * it that is suitable to be used by the command subsystem.
! 541: *
! 542: * @param string Command format string.
! 543: * @param descstr Description string.
! 544: * @return A vector of struct cmd_token representing the given command,
! 545: * or NULL on error.
! 546: */
! 547: static vector
! 548: cmd_parse_format(const char *string, const char *descstr)
! 549: {
! 550: struct format_parser_state state;
! 551:
! 552: if (string == NULL)
! 553: return NULL;
! 554:
! 555: memset(&state, 0, sizeof(state));
! 556: state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
! 557: state.cp = state.string = string;
! 558: state.dp = descstr;
! 559:
! 560: while (1)
! 561: {
! 562: while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
! 563: state.cp++;
! 564:
! 565: switch (state.cp[0])
! 566: {
! 567: case '\0':
! 568: if (state.in_keyword
! 569: || state.in_multiple)
! 570: format_parser_error(&state, "Unclosed group/keyword");
! 571: return state.topvect;
! 572: case '{':
! 573: format_parser_begin_keyword(&state);
! 574: break;
! 575: case '(':
! 576: format_parser_begin_multiple(&state);
! 577: break;
! 578: case '}':
! 579: format_parser_end_keyword(&state);
! 580: break;
! 581: case ')':
! 582: format_parser_end_multiple(&state);
! 583: break;
! 584: case '|':
! 585: format_parser_handle_pipe(&state);
! 586: break;
! 587: default:
! 588: format_parser_read_word(&state);
! 589: }
1.1 misho 590: }
591: }
592:
593: /* Return prompt character of specified node. */
594: const char *
595: cmd_prompt (enum node_type node)
596: {
597: struct cmd_node *cnode;
598:
599: cnode = vector_slot (cmdvec, node);
600: return cnode->prompt;
601: }
602:
603: /* Install a command into a node. */
604: void
605: install_element (enum node_type ntype, struct cmd_element *cmd)
606: {
607: struct cmd_node *cnode;
608:
609: /* cmd_init hasn't been called */
610: if (!cmdvec)
611: return;
612:
613: cnode = vector_slot (cmdvec, ntype);
614:
615: if (cnode == NULL)
616: {
617: fprintf (stderr, "Command node %d doesn't exist, please check it\n",
618: ntype);
619: exit (1);
620: }
621:
622: vector_set (cnode->cmd_vector, cmd);
1.1.1.4 ! misho 623: if (cmd->tokens == NULL)
! 624: cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
1.1 misho 625: }
626:
627: static const unsigned char itoa64[] =
628: "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
629:
630: static void
631: to64(char *s, long v, int n)
632: {
633: while (--n >= 0)
634: {
635: *s++ = itoa64[v&0x3f];
636: v >>= 6;
637: }
638: }
639:
640: static char *
641: zencrypt (const char *passwd)
642: {
643: char salt[6];
644: struct timeval tv;
645: char *crypt (const char *, const char *);
646:
647: gettimeofday(&tv,0);
648:
649: to64(&salt[0], random(), 3);
650: to64(&salt[3], tv.tv_usec, 3);
651: salt[5] = '\0';
652:
653: return crypt (passwd, salt);
654: }
655:
656: /* This function write configuration of this host. */
657: static int
658: config_write_host (struct vty *vty)
659: {
660: if (host.name)
661: vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
662:
663: if (host.encrypt)
664: {
665: if (host.password_encrypt)
666: vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
667: if (host.enable_encrypt)
668: vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
669: }
670: else
671: {
672: if (host.password)
673: vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
674: if (host.enable)
675: vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
676: }
677:
678: if (zlog_default->default_lvl != LOG_DEBUG)
679: {
680: vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
681: VTY_NEWLINE);
682: vty_out (vty, "log trap %s%s",
683: zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
684: }
685:
686: if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
687: {
688: vty_out (vty, "log file %s", host.logfile);
689: if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
690: vty_out (vty, " %s",
691: zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
692: vty_out (vty, "%s", VTY_NEWLINE);
693: }
694:
695: if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
696: {
697: vty_out (vty, "log stdout");
698: if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
699: vty_out (vty, " %s",
700: zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
701: vty_out (vty, "%s", VTY_NEWLINE);
702: }
703:
704: if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
705: vty_out(vty,"no log monitor%s",VTY_NEWLINE);
706: else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
707: vty_out(vty,"log monitor %s%s",
708: zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
709:
710: if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
711: {
712: vty_out (vty, "log syslog");
713: if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
714: vty_out (vty, " %s",
715: zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
716: vty_out (vty, "%s", VTY_NEWLINE);
717: }
718:
719: if (zlog_default->facility != LOG_DAEMON)
720: vty_out (vty, "log facility %s%s",
721: facility_name(zlog_default->facility), VTY_NEWLINE);
722:
723: if (zlog_default->record_priority == 1)
724: vty_out (vty, "log record-priority%s", VTY_NEWLINE);
725:
726: if (zlog_default->timestamp_precision > 0)
727: vty_out (vty, "log timestamp precision %d%s",
728: zlog_default->timestamp_precision, VTY_NEWLINE);
729:
730: if (host.advanced)
731: vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
732:
733: if (host.encrypt)
734: vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
735:
736: if (host.lines >= 0)
737: vty_out (vty, "service terminal-length %d%s", host.lines,
738: VTY_NEWLINE);
739:
740: if (host.motdfile)
741: vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
742: else if (! host.motd)
743: vty_out (vty, "no banner motd%s", VTY_NEWLINE);
744:
745: return 1;
746: }
747:
748: /* Utility function for getting command vector. */
749: static vector
750: cmd_node_vector (vector v, enum node_type ntype)
751: {
752: struct cmd_node *cnode = vector_slot (v, ntype);
753: return cnode->cmd_vector;
754: }
755:
756: #if 0
757: /* Filter command vector by symbol. This function is not actually used;
758: * should it be deleted? */
759: static int
760: cmd_filter_by_symbol (char *command, char *symbol)
761: {
762: int i, lim;
763:
764: if (strcmp (symbol, "IPV4_ADDRESS") == 0)
765: {
766: i = 0;
767: lim = strlen (command);
768: while (i < lim)
769: {
770: if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
771: return 1;
772: i++;
773: }
774: return 0;
775: }
776: if (strcmp (symbol, "STRING") == 0)
777: {
778: i = 0;
779: lim = strlen (command);
780: while (i < lim)
781: {
782: if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
783: return 1;
784: i++;
785: }
786: return 0;
787: }
788: if (strcmp (symbol, "IFNAME") == 0)
789: {
790: i = 0;
791: lim = strlen (command);
792: while (i < lim)
793: {
794: if (! isalnum ((int) command[i]))
795: return 1;
796: i++;
797: }
798: return 0;
799: }
800: return 0;
801: }
802: #endif
803:
804: /* Completion match types. */
805: enum match_type
806: {
807: no_match,
808: extend_match,
809: ipv4_prefix_match,
810: ipv4_match,
811: ipv6_prefix_match,
812: ipv6_match,
813: range_match,
814: vararg_match,
815: partly_match,
816: exact_match
817: };
818:
819: static enum match_type
820: cmd_ipv4_match (const char *str)
821: {
822: const char *sp;
823: int dots = 0, nums = 0;
824: char buf[4];
825:
826: if (str == NULL)
827: return partly_match;
828:
829: for (;;)
830: {
831: memset (buf, 0, sizeof (buf));
832: sp = str;
833: while (*str != '\0')
834: {
835: if (*str == '.')
836: {
837: if (dots >= 3)
838: return no_match;
839:
840: if (*(str + 1) == '.')
841: return no_match;
842:
843: if (*(str + 1) == '\0')
844: return partly_match;
845:
846: dots++;
847: break;
848: }
849: if (!isdigit ((int) *str))
850: return no_match;
851:
852: str++;
853: }
854:
855: if (str - sp > 3)
856: return no_match;
857:
858: strncpy (buf, sp, str - sp);
859: if (atoi (buf) > 255)
860: return no_match;
861:
862: nums++;
863:
864: if (*str == '\0')
865: break;
866:
867: str++;
868: }
869:
870: if (nums < 4)
871: return partly_match;
872:
873: return exact_match;
874: }
875:
876: static enum match_type
877: cmd_ipv4_prefix_match (const char *str)
878: {
879: const char *sp;
880: int dots = 0;
881: char buf[4];
882:
883: if (str == NULL)
884: return partly_match;
885:
886: for (;;)
887: {
888: memset (buf, 0, sizeof (buf));
889: sp = str;
890: while (*str != '\0' && *str != '/')
891: {
892: if (*str == '.')
893: {
894: if (dots == 3)
895: return no_match;
896:
897: if (*(str + 1) == '.' || *(str + 1) == '/')
898: return no_match;
899:
900: if (*(str + 1) == '\0')
901: return partly_match;
902:
903: dots++;
904: break;
905: }
906:
907: if (!isdigit ((int) *str))
908: return no_match;
909:
910: str++;
911: }
912:
913: if (str - sp > 3)
914: return no_match;
915:
916: strncpy (buf, sp, str - sp);
917: if (atoi (buf) > 255)
918: return no_match;
919:
920: if (dots == 3)
921: {
922: if (*str == '/')
923: {
924: if (*(str + 1) == '\0')
925: return partly_match;
926:
927: str++;
928: break;
929: }
930: else if (*str == '\0')
931: return partly_match;
932: }
933:
934: if (*str == '\0')
935: return partly_match;
936:
937: str++;
938: }
939:
940: sp = str;
941: while (*str != '\0')
942: {
943: if (!isdigit ((int) *str))
944: return no_match;
945:
946: str++;
947: }
948:
949: if (atoi (sp) > 32)
950: return no_match;
951:
952: return exact_match;
953: }
954:
955: #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
956: #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
957: #define STATE_START 1
958: #define STATE_COLON 2
959: #define STATE_DOUBLE 3
960: #define STATE_ADDR 4
961: #define STATE_DOT 5
962: #define STATE_SLASH 6
963: #define STATE_MASK 7
964:
965: #ifdef HAVE_IPV6
966:
967: static enum match_type
968: cmd_ipv6_match (const char *str)
969: {
970: struct sockaddr_in6 sin6_dummy;
971: int ret;
972:
973: if (str == NULL)
974: return partly_match;
975:
976: if (strspn (str, IPV6_ADDR_STR) != strlen (str))
977: return no_match;
978:
979: /* use inet_pton that has a better support,
980: * for example inet_pton can support the automatic addresses:
981: * ::1.2.3.4
982: */
983: ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
984:
985: if (ret == 1)
986: return exact_match;
987:
1.1.1.3 misho 988: return no_match;
1.1 misho 989: }
990:
991: static enum match_type
992: cmd_ipv6_prefix_match (const char *str)
993: {
994: int state = STATE_START;
995: int colons = 0, nums = 0, double_colon = 0;
996: int mask;
997: const char *sp = NULL;
998: char *endptr = NULL;
999:
1000: if (str == NULL)
1001: return partly_match;
1002:
1003: if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
1004: return no_match;
1005:
1006: while (*str != '\0' && state != STATE_MASK)
1007: {
1008: switch (state)
1009: {
1010: case STATE_START:
1011: if (*str == ':')
1012: {
1013: if (*(str + 1) != ':' && *(str + 1) != '\0')
1014: return no_match;
1015: colons--;
1016: state = STATE_COLON;
1017: }
1018: else
1019: {
1020: sp = str;
1021: state = STATE_ADDR;
1022: }
1023:
1024: continue;
1025: case STATE_COLON:
1026: colons++;
1027: if (*(str + 1) == '/')
1028: return no_match;
1029: else if (*(str + 1) == ':')
1030: state = STATE_DOUBLE;
1031: else
1032: {
1033: sp = str + 1;
1034: state = STATE_ADDR;
1035: }
1036: break;
1037: case STATE_DOUBLE:
1038: if (double_colon)
1039: return no_match;
1040:
1041: if (*(str + 1) == ':')
1042: return no_match;
1043: else
1044: {
1045: if (*(str + 1) != '\0' && *(str + 1) != '/')
1046: colons++;
1047: sp = str + 1;
1048:
1049: if (*(str + 1) == '/')
1050: state = STATE_SLASH;
1051: else
1052: state = STATE_ADDR;
1053: }
1054:
1055: double_colon++;
1056: nums += 1;
1057: break;
1058: case STATE_ADDR:
1059: if (*(str + 1) == ':' || *(str + 1) == '.'
1060: || *(str + 1) == '\0' || *(str + 1) == '/')
1061: {
1062: if (str - sp > 3)
1063: return no_match;
1064:
1065: for (; sp <= str; sp++)
1066: if (*sp == '/')
1067: return no_match;
1068:
1069: nums++;
1070:
1071: if (*(str + 1) == ':')
1072: state = STATE_COLON;
1073: else if (*(str + 1) == '.')
1.1.1.3 misho 1074: {
1075: if (colons || double_colon)
1076: state = STATE_DOT;
1077: else
1078: return no_match;
1079: }
1.1 misho 1080: else if (*(str + 1) == '/')
1081: state = STATE_SLASH;
1082: }
1083: break;
1084: case STATE_DOT:
1085: state = STATE_ADDR;
1086: break;
1087: case STATE_SLASH:
1088: if (*(str + 1) == '\0')
1089: return partly_match;
1090:
1091: state = STATE_MASK;
1092: break;
1093: default:
1094: break;
1095: }
1096:
1097: if (nums > 11)
1098: return no_match;
1099:
1100: if (colons > 7)
1101: return no_match;
1102:
1103: str++;
1104: }
1105:
1106: if (state < STATE_MASK)
1107: return partly_match;
1108:
1109: mask = strtol (str, &endptr, 10);
1110: if (*endptr != '\0')
1111: return no_match;
1112:
1113: if (mask < 0 || mask > 128)
1114: return no_match;
1115:
1116: /* I don't know why mask < 13 makes command match partly.
1117: Forgive me to make this comments. I Want to set static default route
1118: because of lack of function to originate default in ospf6d; sorry
1119: yasu
1120: if (mask < 13)
1121: return partly_match;
1122: */
1123:
1124: return exact_match;
1125: }
1126:
1127: #endif /* HAVE_IPV6 */
1128:
1129: #define DECIMAL_STRLEN_MAX 10
1130:
1131: static int
1132: cmd_range_match (const char *range, const char *str)
1133: {
1134: char *p;
1135: char buf[DECIMAL_STRLEN_MAX + 1];
1136: char *endptr = NULL;
1137: unsigned long min, max, val;
1138:
1139: if (str == NULL)
1140: return 1;
1141:
1142: val = strtoul (str, &endptr, 10);
1143: if (*endptr != '\0')
1144: return 0;
1145:
1146: range++;
1147: p = strchr (range, '-');
1148: if (p == NULL)
1149: return 0;
1150: if (p - range > DECIMAL_STRLEN_MAX)
1151: return 0;
1152: strncpy (buf, range, p - range);
1153: buf[p - range] = '\0';
1154: min = strtoul (buf, &endptr, 10);
1155: if (*endptr != '\0')
1156: return 0;
1157:
1158: range = p + 1;
1159: p = strchr (range, '>');
1160: if (p == NULL)
1161: return 0;
1162: if (p - range > DECIMAL_STRLEN_MAX)
1163: return 0;
1164: strncpy (buf, range, p - range);
1165: buf[p - range] = '\0';
1166: max = strtoul (buf, &endptr, 10);
1167: if (*endptr != '\0')
1168: return 0;
1169:
1170: if (val < min || val > max)
1171: return 0;
1172:
1173: return 1;
1174: }
1175:
1176: static enum match_type
1.1.1.4 ! misho 1177: cmd_word_match(struct cmd_token *token,
! 1178: enum filter_type filter,
! 1179: const char *word)
1.1 misho 1180: {
1181: const char *str;
1182: enum match_type match_type;
1183:
1.1.1.4 ! misho 1184: str = token->cmd;
1.1 misho 1185:
1.1.1.4 ! misho 1186: if (filter == FILTER_RELAXED)
! 1187: if (!word || !strlen(word))
! 1188: return partly_match;
1.1 misho 1189:
1.1.1.4 ! misho 1190: if (!word)
! 1191: return no_match;
1.1 misho 1192:
1.1.1.4 ! misho 1193: switch (token->terminal)
! 1194: {
! 1195: case TERMINAL_VARARG:
! 1196: return vararg_match;
1.1 misho 1197:
1.1.1.4 ! misho 1198: case TERMINAL_RANGE:
! 1199: if (cmd_range_match(str, word))
! 1200: return range_match;
! 1201: break;
! 1202:
! 1203: case TERMINAL_IPV6:
! 1204: match_type = cmd_ipv6_match(word);
! 1205: if ((filter == FILTER_RELAXED && match_type != no_match)
! 1206: || (filter == FILTER_STRICT && match_type == exact_match))
! 1207: return ipv6_match;
! 1208: break;
! 1209:
! 1210: case TERMINAL_IPV6_PREFIX:
! 1211: match_type = cmd_ipv6_prefix_match(word);
! 1212: if ((filter == FILTER_RELAXED && match_type != no_match)
! 1213: || (filter == FILTER_STRICT && match_type == exact_match))
! 1214: return ipv6_prefix_match;
! 1215: break;
! 1216:
! 1217: case TERMINAL_IPV4:
! 1218: match_type = cmd_ipv4_match(word);
! 1219: if ((filter == FILTER_RELAXED && match_type != no_match)
! 1220: || (filter == FILTER_STRICT && match_type == exact_match))
! 1221: return ipv4_match;
! 1222: break;
! 1223:
! 1224: case TERMINAL_IPV4_PREFIX:
! 1225: match_type = cmd_ipv4_prefix_match(word);
! 1226: if ((filter == FILTER_RELAXED && match_type != no_match)
! 1227: || (filter == FILTER_STRICT && match_type == exact_match))
! 1228: return ipv4_prefix_match;
! 1229: break;
! 1230:
! 1231: case TERMINAL_OPTION:
! 1232: case TERMINAL_VARIABLE:
! 1233: return extend_match;
1.1 misho 1234:
1.1.1.4 ! misho 1235: case TERMINAL_LITERAL:
! 1236: if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
! 1237: {
! 1238: if (!strcmp(str, word))
! 1239: return exact_match;
! 1240: return partly_match;
! 1241: }
! 1242: if (filter == FILTER_STRICT && !strcmp(str, word))
! 1243: return exact_match;
! 1244: break;
1.1 misho 1245:
1.1.1.4 ! misho 1246: default:
! 1247: assert (0);
! 1248: }
1.1 misho 1249:
1.1.1.4 ! misho 1250: return no_match;
! 1251: }
! 1252:
! 1253: struct cmd_matcher
! 1254: {
! 1255: struct cmd_element *cmd; /* The command element the matcher is using */
! 1256: enum filter_type filter; /* Whether to use strict or relaxed matching */
! 1257: vector vline; /* The tokenized commandline which is to be matched */
! 1258: unsigned int index; /* The index up to which matching should be done */
! 1259:
! 1260: /* If set, construct a list of matches at the position given by index */
! 1261: enum match_type *match_type;
! 1262: vector *match;
! 1263:
! 1264: unsigned int word_index; /* iterating over vline */
! 1265: };
! 1266:
! 1267: static int
! 1268: push_argument(int *argc, const char **argv, const char *arg)
! 1269: {
! 1270: if (!arg || !strlen(arg))
! 1271: arg = NULL;
! 1272:
! 1273: if (!argc || !argv)
! 1274: return 0;
! 1275:
! 1276: if (*argc >= CMD_ARGC_MAX)
! 1277: return -1;
! 1278:
! 1279: argv[(*argc)++] = arg;
! 1280: return 0;
! 1281: }
! 1282:
! 1283: static void
! 1284: cmd_matcher_record_match(struct cmd_matcher *matcher,
! 1285: enum match_type match_type,
! 1286: struct cmd_token *token)
! 1287: {
! 1288: if (matcher->word_index != matcher->index)
! 1289: return;
! 1290:
! 1291: if (matcher->match)
! 1292: {
! 1293: if (!*matcher->match)
! 1294: *matcher->match = vector_init(VECTOR_MIN_SIZE);
! 1295: vector_set(*matcher->match, token);
! 1296: }
! 1297:
! 1298: if (matcher->match_type)
! 1299: {
! 1300: if (match_type > *matcher->match_type)
! 1301: *matcher->match_type = match_type;
! 1302: }
! 1303: }
! 1304:
! 1305: static int
! 1306: cmd_matcher_words_left(struct cmd_matcher *matcher)
! 1307: {
! 1308: return matcher->word_index < vector_active(matcher->vline);
! 1309: }
! 1310:
! 1311: static const char*
! 1312: cmd_matcher_get_word(struct cmd_matcher *matcher)
! 1313: {
! 1314: assert(cmd_matcher_words_left(matcher));
! 1315:
! 1316: return vector_slot(matcher->vline, matcher->word_index);
! 1317: }
! 1318:
! 1319: static enum matcher_rv
! 1320: cmd_matcher_match_terminal(struct cmd_matcher *matcher,
! 1321: struct cmd_token *token,
! 1322: int *argc, const char **argv)
! 1323: {
! 1324: const char *word;
! 1325: enum match_type word_match;
! 1326:
! 1327: assert(token->type == TOKEN_TERMINAL);
! 1328:
! 1329: if (!cmd_matcher_words_left(matcher))
! 1330: {
! 1331: if (token->terminal == TERMINAL_OPTION)
! 1332: return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
! 1333: else
! 1334: return MATCHER_INCOMPLETE;
! 1335: }
! 1336:
! 1337: word = cmd_matcher_get_word(matcher);
! 1338: word_match = cmd_word_match(token, matcher->filter, word);
! 1339: if (word_match == no_match)
! 1340: return MATCHER_NO_MATCH;
! 1341:
! 1342: /* We have to record the input word as argument if it matched
! 1343: * against a variable. */
! 1344: if (TERMINAL_RECORD (token->terminal))
! 1345: {
! 1346: if (push_argument(argc, argv, word))
! 1347: return MATCHER_EXCEED_ARGC_MAX;
! 1348: }
! 1349:
! 1350: cmd_matcher_record_match(matcher, word_match, token);
! 1351:
! 1352: matcher->word_index++;
! 1353:
! 1354: /* A vararg token should consume all left over words as arguments */
! 1355: if (token->terminal == TERMINAL_VARARG)
! 1356: while (cmd_matcher_words_left(matcher))
! 1357: {
! 1358: word = cmd_matcher_get_word(matcher);
! 1359: if (word && strlen(word))
! 1360: push_argument(argc, argv, word);
! 1361: matcher->word_index++;
1.1 misho 1362: }
1.1.1.4 ! misho 1363:
! 1364: return MATCHER_OK;
1.1 misho 1365: }
1366:
1.1.1.4 ! misho 1367: static enum matcher_rv
! 1368: cmd_matcher_match_multiple(struct cmd_matcher *matcher,
! 1369: struct cmd_token *token,
! 1370: int *argc, const char **argv)
! 1371: {
! 1372: enum match_type multiple_match;
! 1373: unsigned int multiple_index;
! 1374: const char *word;
! 1375: const char *arg = NULL;
! 1376: struct cmd_token *word_token;
! 1377: enum match_type word_match;
! 1378:
! 1379: assert(token->type == TOKEN_MULTIPLE);
! 1380:
! 1381: multiple_match = no_match;
! 1382:
! 1383: if (!cmd_matcher_words_left(matcher))
! 1384: return MATCHER_INCOMPLETE;
! 1385:
! 1386: word = cmd_matcher_get_word(matcher);
! 1387: for (multiple_index = 0;
! 1388: multiple_index < vector_active(token->multiple);
! 1389: multiple_index++)
! 1390: {
! 1391: word_token = vector_slot(token->multiple, multiple_index);
! 1392:
! 1393: word_match = cmd_word_match(word_token, matcher->filter, word);
! 1394: if (word_match == no_match)
! 1395: continue;
! 1396:
! 1397: cmd_matcher_record_match(matcher, word_match, word_token);
! 1398:
! 1399: if (word_match > multiple_match)
! 1400: {
! 1401: multiple_match = word_match;
! 1402: arg = word;
! 1403: }
! 1404: /* To mimic the behavior of the old command implementation, we
! 1405: * tolerate any ambiguities here :/ */
! 1406: }
! 1407:
! 1408: matcher->word_index++;
! 1409:
! 1410: if (multiple_match == no_match)
! 1411: return MATCHER_NO_MATCH;
! 1412:
! 1413: if (push_argument(argc, argv, arg))
! 1414: return MATCHER_EXCEED_ARGC_MAX;
! 1415:
! 1416: return MATCHER_OK;
! 1417: }
! 1418:
! 1419: static enum matcher_rv
! 1420: cmd_matcher_read_keywords(struct cmd_matcher *matcher,
! 1421: struct cmd_token *token,
! 1422: vector args_vector)
! 1423: {
! 1424: unsigned int i;
! 1425: unsigned long keyword_mask;
! 1426: unsigned int keyword_found;
! 1427: enum match_type keyword_match;
! 1428: enum match_type word_match;
! 1429: vector keyword_vector;
! 1430: struct cmd_token *word_token;
! 1431: const char *word;
! 1432: int keyword_argc;
! 1433: const char **keyword_argv;
! 1434: enum matcher_rv rv = MATCHER_NO_MATCH;
! 1435:
! 1436: keyword_mask = 0;
! 1437: while (1)
! 1438: {
! 1439: if (!cmd_matcher_words_left(matcher))
! 1440: return MATCHER_OK;
! 1441:
! 1442: word = cmd_matcher_get_word(matcher);
! 1443:
! 1444: keyword_found = -1;
! 1445: keyword_match = no_match;
! 1446: for (i = 0; i < vector_active(token->keyword); i++)
! 1447: {
! 1448: if (keyword_mask & (1 << i))
! 1449: continue;
! 1450:
! 1451: keyword_vector = vector_slot(token->keyword, i);
! 1452: word_token = vector_slot(keyword_vector, 0);
! 1453:
! 1454: word_match = cmd_word_match(word_token, matcher->filter, word);
! 1455: if (word_match == no_match)
! 1456: continue;
! 1457:
! 1458: cmd_matcher_record_match(matcher, word_match, word_token);
! 1459:
! 1460: if (word_match > keyword_match)
! 1461: {
! 1462: keyword_match = word_match;
! 1463: keyword_found = i;
! 1464: }
! 1465: else if (word_match == keyword_match)
! 1466: {
! 1467: if (matcher->word_index != matcher->index || args_vector)
! 1468: return MATCHER_AMBIGUOUS;
! 1469: }
! 1470: }
! 1471:
! 1472: if (keyword_found == (unsigned int)-1)
! 1473: return MATCHER_NO_MATCH;
! 1474:
! 1475: matcher->word_index++;
! 1476:
! 1477: if (matcher->word_index > matcher->index)
! 1478: return MATCHER_OK;
! 1479:
! 1480: keyword_mask |= (1 << keyword_found);
! 1481:
! 1482: if (args_vector)
! 1483: {
! 1484: keyword_argc = 0;
! 1485: keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
! 1486: /* We use -1 as a marker for unused fields as NULL might be a valid value */
! 1487: for (i = 0; i < CMD_ARGC_MAX + 1; i++)
! 1488: keyword_argv[i] = (void*)-1;
! 1489: vector_set_index(args_vector, keyword_found, keyword_argv);
! 1490: }
! 1491: else
! 1492: {
! 1493: keyword_argv = NULL;
! 1494: }
! 1495:
! 1496: keyword_vector = vector_slot(token->keyword, keyword_found);
! 1497: /* the keyword itself is at 0. We are only interested in the arguments,
! 1498: * so start counting at 1. */
! 1499: for (i = 1; i < vector_active(keyword_vector); i++)
! 1500: {
! 1501: word_token = vector_slot(keyword_vector, i);
! 1502:
! 1503: switch (word_token->type)
! 1504: {
! 1505: case TOKEN_TERMINAL:
! 1506: rv = cmd_matcher_match_terminal(matcher, word_token,
! 1507: &keyword_argc, keyword_argv);
! 1508: break;
! 1509: case TOKEN_MULTIPLE:
! 1510: rv = cmd_matcher_match_multiple(matcher, word_token,
! 1511: &keyword_argc, keyword_argv);
! 1512: break;
! 1513: case TOKEN_KEYWORD:
! 1514: assert(!"Keywords should never be nested.");
! 1515: break;
! 1516: }
! 1517:
! 1518: if (MATCHER_ERROR(rv))
! 1519: return rv;
! 1520:
! 1521: if (matcher->word_index > matcher->index)
! 1522: return MATCHER_OK;
! 1523: }
! 1524: }
! 1525: /* not reached */
! 1526: }
! 1527:
! 1528: static enum matcher_rv
! 1529: cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
! 1530: struct cmd_token *token,
! 1531: int *argc, const char **argv,
! 1532: vector keyword_args_vector)
! 1533: {
! 1534: unsigned int i, j;
! 1535: const char **keyword_args;
! 1536: vector keyword_vector;
! 1537: struct cmd_token *word_token;
! 1538: const char *arg;
! 1539: enum matcher_rv rv;
! 1540:
! 1541: rv = MATCHER_OK;
! 1542:
! 1543: if (keyword_args_vector == NULL)
! 1544: return rv;
! 1545:
! 1546: for (i = 0; i < vector_active(token->keyword); i++)
! 1547: {
! 1548: keyword_vector = vector_slot(token->keyword, i);
! 1549: keyword_args = vector_lookup(keyword_args_vector, i);
! 1550:
! 1551: if (vector_active(keyword_vector) == 1)
! 1552: {
! 1553: /* this is a keyword without arguments */
! 1554: if (keyword_args)
! 1555: {
! 1556: word_token = vector_slot(keyword_vector, 0);
! 1557: arg = word_token->cmd;
! 1558: }
! 1559: else
! 1560: {
! 1561: arg = NULL;
! 1562: }
! 1563:
! 1564: if (push_argument(argc, argv, arg))
! 1565: rv = MATCHER_EXCEED_ARGC_MAX;
! 1566: }
! 1567: else
! 1568: {
! 1569: /* this is a keyword with arguments */
! 1570: if (keyword_args)
! 1571: {
! 1572: /* the keyword was present, so just fill in the arguments */
! 1573: for (j = 0; keyword_args[j] != (void*)-1; j++)
! 1574: if (push_argument(argc, argv, keyword_args[j]))
! 1575: rv = MATCHER_EXCEED_ARGC_MAX;
! 1576: XFREE(MTYPE_TMP, keyword_args);
! 1577: }
! 1578: else
! 1579: {
! 1580: /* the keyword was not present, insert NULL for the arguments
! 1581: * the keyword would have taken. */
! 1582: for (j = 1; j < vector_active(keyword_vector); j++)
! 1583: {
! 1584: word_token = vector_slot(keyword_vector, j);
! 1585: if ((word_token->type == TOKEN_TERMINAL
! 1586: && TERMINAL_RECORD (word_token->terminal))
! 1587: || word_token->type == TOKEN_MULTIPLE)
! 1588: {
! 1589: if (push_argument(argc, argv, NULL))
! 1590: rv = MATCHER_EXCEED_ARGC_MAX;
! 1591: }
! 1592: }
! 1593: }
! 1594: }
! 1595: }
! 1596: vector_free(keyword_args_vector);
! 1597: return rv;
! 1598: }
! 1599:
! 1600: static enum matcher_rv
! 1601: cmd_matcher_match_keyword(struct cmd_matcher *matcher,
! 1602: struct cmd_token *token,
! 1603: int *argc, const char **argv)
! 1604: {
! 1605: vector keyword_args_vector;
! 1606: enum matcher_rv reader_rv;
! 1607: enum matcher_rv builder_rv;
! 1608:
! 1609: assert(token->type == TOKEN_KEYWORD);
! 1610:
! 1611: if (argc && argv)
! 1612: keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
! 1613: else
! 1614: keyword_args_vector = NULL;
! 1615:
! 1616: reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
! 1617: builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
! 1618: argv, keyword_args_vector);
! 1619: /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
! 1620:
! 1621: if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
! 1622: return builder_rv;
! 1623:
! 1624: return reader_rv;
! 1625: }
! 1626:
! 1627: static void
! 1628: cmd_matcher_init(struct cmd_matcher *matcher,
! 1629: struct cmd_element *cmd,
! 1630: enum filter_type filter,
! 1631: vector vline,
! 1632: unsigned int index,
! 1633: enum match_type *match_type,
! 1634: vector *match)
! 1635: {
! 1636: memset(matcher, 0, sizeof(*matcher));
! 1637:
! 1638: matcher->cmd = cmd;
! 1639: matcher->filter = filter;
! 1640: matcher->vline = vline;
! 1641: matcher->index = index;
! 1642:
! 1643: matcher->match_type = match_type;
! 1644: if (matcher->match_type)
! 1645: *matcher->match_type = no_match;
! 1646: matcher->match = match;
! 1647:
! 1648: matcher->word_index = 0;
! 1649: }
! 1650:
! 1651: static enum matcher_rv
! 1652: cmd_element_match(struct cmd_element *cmd_element,
! 1653: enum filter_type filter,
! 1654: vector vline,
! 1655: unsigned int index,
! 1656: enum match_type *match_type,
! 1657: vector *match,
! 1658: int *argc,
! 1659: const char **argv)
! 1660: {
! 1661: struct cmd_matcher matcher;
! 1662: unsigned int token_index;
! 1663: enum matcher_rv rv = MATCHER_NO_MATCH;
! 1664:
! 1665: cmd_matcher_init(&matcher, cmd_element, filter,
! 1666: vline, index, match_type, match);
! 1667:
! 1668: if (argc != NULL)
! 1669: *argc = 0;
! 1670:
! 1671: for (token_index = 0;
! 1672: token_index < vector_active(cmd_element->tokens);
! 1673: token_index++)
! 1674: {
! 1675: struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
! 1676:
! 1677: switch (token->type)
! 1678: {
! 1679: case TOKEN_TERMINAL:
! 1680: rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
! 1681: break;
! 1682: case TOKEN_MULTIPLE:
! 1683: rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
! 1684: break;
! 1685: case TOKEN_KEYWORD:
! 1686: rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
! 1687: }
! 1688:
! 1689: if (MATCHER_ERROR(rv))
! 1690: return rv;
! 1691:
! 1692: if (matcher.word_index > index)
! 1693: return MATCHER_OK;
! 1694: }
! 1695:
! 1696: /* return MATCHER_COMPLETE if all words were consumed */
! 1697: if (matcher.word_index >= vector_active(vline))
! 1698: return MATCHER_COMPLETE;
! 1699:
! 1700: /* return MATCHER_COMPLETE also if only an empty word is left. */
! 1701: if (matcher.word_index == vector_active(vline) - 1
! 1702: && (!vector_slot(vline, matcher.word_index)
! 1703: || !strlen((char*)vector_slot(vline, matcher.word_index))))
! 1704: return MATCHER_COMPLETE;
! 1705:
! 1706: return MATCHER_NO_MATCH; /* command is too long to match */
! 1707: }
! 1708:
! 1709: /**
! 1710: * Filter a given vector of commands against a given commandline and
! 1711: * calculate possible completions.
! 1712: *
! 1713: * @param commands A vector of struct cmd_element*. Commands that don't
! 1714: * match against the given command line will be overwritten
! 1715: * with NULL in that vector.
! 1716: * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
! 1717: * determines how incomplete commands are handled, compare with
! 1718: * cmd_word_match for details.
! 1719: * @param vline A vector of char* containing the tokenized commandline.
! 1720: * @param index Only match up to the given token of the commandline.
! 1721: * @param match_type Record the type of the best match here.
! 1722: * @param matches Record the matches here. For each cmd_element in the commands
! 1723: * vector, a match vector will be created in the matches vector.
! 1724: * That vector will contain all struct command_token* of the
! 1725: * cmd_element which matched against the given vline at the given
! 1726: * index.
! 1727: * @return A code specifying if an error occured. If all went right, it's
! 1728: * CMD_SUCCESS.
! 1729: */
! 1730: static int
! 1731: cmd_vector_filter(vector commands,
! 1732: enum filter_type filter,
! 1733: vector vline,
! 1734: unsigned int index,
! 1735: enum match_type *match_type,
! 1736: vector *matches)
1.1 misho 1737: {
1738: unsigned int i;
1739: struct cmd_element *cmd_element;
1.1.1.4 ! misho 1740: enum match_type best_match;
! 1741: enum match_type element_match;
! 1742: enum matcher_rv matcher_rv;
1.1 misho 1743:
1.1.1.4 ! misho 1744: best_match = no_match;
! 1745: *matches = vector_init(VECTOR_MIN_SIZE);
1.1 misho 1746:
1.1.1.4 ! misho 1747: for (i = 0; i < vector_active (commands); i++)
! 1748: if ((cmd_element = vector_slot (commands, i)) != NULL)
1.1 misho 1749: {
1.1.1.4 ! misho 1750: vector_set_index(*matches, i, NULL);
! 1751: matcher_rv = cmd_element_match(cmd_element, filter,
! 1752: vline, index,
! 1753: &element_match,
! 1754: (vector*)&vector_slot(*matches, i),
! 1755: NULL, NULL);
! 1756: if (MATCHER_ERROR(matcher_rv))
! 1757: {
! 1758: vector_slot(commands, i) = NULL;
! 1759: if (matcher_rv == MATCHER_AMBIGUOUS)
! 1760: return CMD_ERR_AMBIGUOUS;
! 1761: if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
! 1762: return CMD_ERR_EXEED_ARGC_MAX;
! 1763: }
! 1764: else if (element_match > best_match)
! 1765: {
! 1766: best_match = element_match;
! 1767: }
! 1768: }
! 1769: *match_type = best_match;
! 1770: return CMD_SUCCESS;
! 1771: }
1.1 misho 1772:
1.1.1.4 ! misho 1773: /**
! 1774: * Check whether a given commandline is complete if used for a specific
! 1775: * cmd_element.
! 1776: *
! 1777: * @param cmd_element A cmd_element against which the commandline should be
! 1778: * checked.
! 1779: * @param vline The tokenized commandline.
! 1780: * @return 1 if the given commandline is complete, 0 otherwise.
! 1781: */
! 1782: static int
! 1783: cmd_is_complete(struct cmd_element *cmd_element,
! 1784: vector vline)
! 1785: {
! 1786: enum matcher_rv rv;
1.1 misho 1787:
1.1.1.4 ! misho 1788: rv = cmd_element_match(cmd_element,
! 1789: FILTER_RELAXED,
! 1790: vline, -1,
! 1791: NULL, NULL,
! 1792: NULL, NULL);
! 1793: return (rv == MATCHER_COMPLETE);
! 1794: }
! 1795:
! 1796: /**
! 1797: * Parse a given commandline and construct a list of arguments for the
! 1798: * given command_element.
! 1799: *
! 1800: * @param cmd_element The cmd_element for which we want to construct arguments.
! 1801: * @param vline The tokenized commandline.
! 1802: * @param argc Where to store the argument count.
! 1803: * @param argv Where to store the argument list. Should be at least
! 1804: * CMD_ARGC_MAX elements long.
! 1805: * @return CMD_SUCCESS if everything went alright, an error otherwise.
! 1806: */
! 1807: static int
! 1808: cmd_parse(struct cmd_element *cmd_element,
! 1809: vector vline,
! 1810: int *argc, const char **argv)
! 1811: {
! 1812: enum matcher_rv rv = cmd_element_match(cmd_element,
! 1813: FILTER_RELAXED,
! 1814: vline, -1,
! 1815: NULL, NULL,
! 1816: argc, argv);
! 1817: switch (rv)
! 1818: {
! 1819: case MATCHER_COMPLETE:
! 1820: return CMD_SUCCESS;
1.1 misho 1821:
1.1.1.4 ! misho 1822: case MATCHER_NO_MATCH:
! 1823: return CMD_ERR_NO_MATCH;
! 1824:
! 1825: case MATCHER_AMBIGUOUS:
! 1826: return CMD_ERR_AMBIGUOUS;
! 1827:
! 1828: case MATCHER_EXCEED_ARGC_MAX:
! 1829: return CMD_ERR_EXEED_ARGC_MAX;
! 1830:
! 1831: default:
! 1832: return CMD_ERR_INCOMPLETE;
! 1833: }
1.1 misho 1834: }
1835:
1836: /* Check ambiguous match */
1837: static int
1.1.1.4 ! misho 1838: is_cmd_ambiguous (vector cmd_vector,
! 1839: const char *command,
! 1840: vector matches,
! 1841: enum match_type type)
1.1 misho 1842: {
1843: unsigned int i;
1844: unsigned int j;
1845: const char *str = NULL;
1846: const char *matched = NULL;
1.1.1.4 ! misho 1847: vector match_vector;
! 1848: struct cmd_token *cmd_token;
1.1 misho 1849:
1.1.1.4 ! misho 1850: if (command == NULL)
! 1851: command = "";
! 1852:
! 1853: for (i = 0; i < vector_active (matches); i++)
! 1854: if ((match_vector = vector_slot (matches, i)) != NULL)
1.1 misho 1855: {
1856: int match = 0;
1857:
1.1.1.4 ! misho 1858: for (j = 0; j < vector_active (match_vector); j++)
! 1859: if ((cmd_token = vector_slot (match_vector, j)) != NULL)
1.1 misho 1860: {
1861: enum match_type ret;
1.1.1.4 ! misho 1862:
! 1863: assert(cmd_token->type == TOKEN_TERMINAL);
! 1864: if (cmd_token->type != TOKEN_TERMINAL)
! 1865: continue;
! 1866:
! 1867: str = cmd_token->cmd;
1.1 misho 1868:
1869: switch (type)
1870: {
1871: case exact_match:
1.1.1.4 ! misho 1872: if (!TERMINAL_RECORD (cmd_token->terminal)
1.1 misho 1873: && strcmp (command, str) == 0)
1874: match++;
1875: break;
1876: case partly_match:
1.1.1.4 ! misho 1877: if (!TERMINAL_RECORD (cmd_token->terminal)
1.1 misho 1878: && strncmp (command, str, strlen (command)) == 0)
1879: {
1880: if (matched && strcmp (matched, str) != 0)
1881: return 1; /* There is ambiguous match. */
1882: else
1883: matched = str;
1884: match++;
1885: }
1886: break;
1887: case range_match:
1888: if (cmd_range_match (str, command))
1889: {
1890: if (matched && strcmp (matched, str) != 0)
1891: return 1;
1892: else
1893: matched = str;
1894: match++;
1895: }
1896: break;
1897: #ifdef HAVE_IPV6
1898: case ipv6_match:
1.1.1.4 ! misho 1899: if (cmd_token->terminal == TERMINAL_IPV6)
1.1 misho 1900: match++;
1901: break;
1902: case ipv6_prefix_match:
1903: if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1904: {
1905: if (ret == partly_match)
1906: return 2; /* There is incomplete match. */
1907:
1908: match++;
1909: }
1910: break;
1911: #endif /* HAVE_IPV6 */
1912: case ipv4_match:
1.1.1.4 ! misho 1913: if (cmd_token->terminal == TERMINAL_IPV4)
1.1 misho 1914: match++;
1915: break;
1916: case ipv4_prefix_match:
1917: if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1918: {
1919: if (ret == partly_match)
1920: return 2; /* There is incomplete match. */
1921:
1922: match++;
1923: }
1924: break;
1925: case extend_match:
1.1.1.4 ! misho 1926: if (TERMINAL_RECORD (cmd_token->terminal))
1.1 misho 1927: match++;
1928: break;
1929: case no_match:
1930: default:
1931: break;
1932: }
1933: }
1934: if (!match)
1.1.1.4 ! misho 1935: vector_slot (cmd_vector, i) = NULL;
1.1 misho 1936: }
1937: return 0;
1938: }
1939:
1940: /* If src matches dst return dst string, otherwise return NULL */
1941: static const char *
1.1.1.4 ! misho 1942: cmd_entry_function (const char *src, struct cmd_token *token)
1.1 misho 1943: {
1.1.1.4 ! misho 1944: const char *dst = token->cmd;
! 1945:
1.1 misho 1946: /* Skip variable arguments. */
1.1.1.4 ! misho 1947: if (TERMINAL_RECORD (token->terminal))
1.1 misho 1948: return NULL;
1949:
1950: /* In case of 'command \t', given src is NULL string. */
1951: if (src == NULL)
1952: return dst;
1953:
1954: /* Matched with input string. */
1955: if (strncmp (src, dst, strlen (src)) == 0)
1956: return dst;
1957:
1958: return NULL;
1959: }
1960:
1961: /* If src matches dst return dst string, otherwise return NULL */
1962: /* This version will return the dst string always if it is
1963: CMD_VARIABLE for '?' key processing */
1964: static const char *
1.1.1.4 ! misho 1965: cmd_entry_function_desc (const char *src, struct cmd_token *token)
1.1 misho 1966: {
1.1.1.4 ! misho 1967: const char *dst = token->cmd;
1.1 misho 1968:
1.1.1.4 ! misho 1969: switch (token->terminal)
1.1 misho 1970: {
1.1.1.4 ! misho 1971: case TERMINAL_VARARG:
! 1972: return dst;
1.1 misho 1973:
1.1.1.4 ! misho 1974: case TERMINAL_RANGE:
! 1975: if (cmd_range_match (dst, src))
! 1976: return dst;
! 1977: else
! 1978: return NULL;
! 1979:
! 1980: case TERMINAL_IPV6:
! 1981: if (cmd_ipv6_match (src))
! 1982: return dst;
! 1983: else
! 1984: return NULL;
! 1985:
! 1986: case TERMINAL_IPV6_PREFIX:
! 1987: if (cmd_ipv6_prefix_match (src))
! 1988: return dst;
! 1989: else
! 1990: return NULL;
! 1991:
! 1992: case TERMINAL_IPV4:
! 1993: if (cmd_ipv4_match (src))
! 1994: return dst;
! 1995: else
! 1996: return NULL;
! 1997:
! 1998: case TERMINAL_IPV4_PREFIX:
! 1999: if (cmd_ipv4_prefix_match (src))
! 2000: return dst;
! 2001: else
! 2002: return NULL;
! 2003:
! 2004: /* Optional or variable commands always match on '?' */
! 2005: case TERMINAL_OPTION:
! 2006: case TERMINAL_VARIABLE:
! 2007: return dst;
! 2008:
! 2009: case TERMINAL_LITERAL:
! 2010: /* In case of 'command \t', given src is NULL string. */
! 2011: if (src == NULL)
! 2012: return dst;
! 2013:
! 2014: if (strncmp (src, dst, strlen (src)) == 0)
! 2015: return dst;
! 2016: else
! 2017: return NULL;
! 2018:
! 2019: default:
! 2020: assert(0);
! 2021: return NULL;
! 2022: }
! 2023: }
! 2024:
! 2025: /**
! 2026: * Check whether a string is already present in a vector of strings.
! 2027: * @param v A vector of char*.
! 2028: * @param str A char*.
! 2029: * @return 0 if str is already present in the vector, 1 otherwise.
! 2030: */
1.1 misho 2031: static int
2032: cmd_unique_string (vector v, const char *str)
2033: {
2034: unsigned int i;
2035: char *match;
2036:
2037: for (i = 0; i < vector_active (v); i++)
2038: if ((match = vector_slot (v, i)) != NULL)
2039: if (strcmp (match, str) == 0)
2040: return 0;
2041: return 1;
2042: }
2043:
1.1.1.4 ! misho 2044: /**
! 2045: * Check whether a struct cmd_token matching a given string is already
! 2046: * present in a vector of struct cmd_token.
! 2047: * @param v A vector of struct cmd_token*.
! 2048: * @param str A char* which should be searched for.
! 2049: * @return 0 if there is a struct cmd_token* with its cmd matching str,
! 2050: * 1 otherwise.
! 2051: */
1.1 misho 2052: static int
2053: desc_unique_string (vector v, const char *str)
2054: {
2055: unsigned int i;
1.1.1.4 ! misho 2056: struct cmd_token *token;
1.1 misho 2057:
2058: for (i = 0; i < vector_active (v); i++)
1.1.1.4 ! misho 2059: if ((token = vector_slot (v, i)) != NULL)
! 2060: if (strcmp (token->cmd, str) == 0)
! 2061: return 0;
! 2062: return 1;
1.1 misho 2063: }
2064:
2065: static int
2066: cmd_try_do_shortcut (enum node_type node, char* first_word) {
2067: if ( first_word != NULL &&
2068: node != AUTH_NODE &&
2069: node != VIEW_NODE &&
2070: node != AUTH_ENABLE_NODE &&
2071: node != ENABLE_NODE &&
2072: node != RESTRICTED_NODE &&
2073: 0 == strcmp( "do", first_word ) )
2074: return 1;
2075: return 0;
2076: }
2077:
1.1.1.4 ! misho 2078: static void
! 2079: cmd_matches_free(vector *matches)
! 2080: {
! 2081: unsigned int i;
! 2082: vector cmd_matches;
! 2083:
! 2084: for (i = 0; i < vector_active(*matches); i++)
! 2085: if ((cmd_matches = vector_slot(*matches, i)) != NULL)
! 2086: vector_free(cmd_matches);
! 2087: vector_free(*matches);
! 2088: *matches = NULL;
! 2089: }
! 2090:
! 2091: static int
! 2092: cmd_describe_cmp(const void *a, const void *b)
! 2093: {
! 2094: const struct cmd_token *first = *(struct cmd_token * const *)a;
! 2095: const struct cmd_token *second = *(struct cmd_token * const *)b;
! 2096:
! 2097: return strcmp(first->cmd, second->cmd);
! 2098: }
! 2099:
! 2100: static void
! 2101: cmd_describe_sort(vector matchvec)
! 2102: {
! 2103: qsort(matchvec->index, vector_active(matchvec),
! 2104: sizeof(void*), cmd_describe_cmp);
! 2105: }
! 2106:
1.1 misho 2107: /* '?' describe command support. */
2108: static vector
2109: cmd_describe_command_real (vector vline, struct vty *vty, int *status)
2110: {
2111: unsigned int i;
2112: vector cmd_vector;
2113: #define INIT_MATCHVEC_SIZE 10
2114: vector matchvec;
2115: struct cmd_element *cmd_element;
2116: unsigned int index;
2117: int ret;
2118: enum match_type match;
2119: char *command;
1.1.1.4 ! misho 2120: vector matches = NULL;
! 2121: vector match_vector;
! 2122: uint32_t command_found = 0;
! 2123: const char *last_word;
1.1 misho 2124:
2125: /* Set index. */
2126: if (vector_active (vline) == 0)
2127: {
2128: *status = CMD_ERR_NO_MATCH;
2129: return NULL;
2130: }
1.1.1.4 ! misho 2131:
! 2132: index = vector_active (vline) - 1;
! 2133:
1.1 misho 2134: /* Make copy vector of current node's command vector. */
2135: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2136:
2137: /* Prepare match vector */
2138: matchvec = vector_init (INIT_MATCHVEC_SIZE);
2139:
1.1.1.4 ! misho 2140: /* Filter commands and build a list how they could possibly continue. */
! 2141: for (i = 0; i <= index; i++)
! 2142: {
! 2143: command = vector_slot (vline, i);
1.1 misho 2144:
1.1.1.4 ! misho 2145: if (matches)
! 2146: cmd_matches_free(&matches);
1.1 misho 2147:
1.1.1.4 ! misho 2148: ret = cmd_vector_filter(cmd_vector,
! 2149: FILTER_RELAXED,
! 2150: vline, i,
! 2151: &match,
! 2152: &matches);
1.1 misho 2153:
1.1.1.4 ! misho 2154: if (ret != CMD_SUCCESS)
! 2155: {
! 2156: vector_free (cmd_vector);
! 2157: vector_free (matchvec);
! 2158: cmd_matches_free(&matches);
! 2159: *status = ret;
! 2160: return NULL;
! 2161: }
! 2162:
! 2163: /* The last match may well be ambigious, so break here */
! 2164: if (i == index)
! 2165: break;
1.1 misho 2166:
1.1.1.4 ! misho 2167: if (match == vararg_match)
! 2168: {
! 2169: /* We found a vararg match - so we can throw out the current matches here
! 2170: * and don't need to continue checking the command input */
! 2171: unsigned int j, k;
! 2172:
! 2173: for (j = 0; j < vector_active (matches); j++)
! 2174: if ((match_vector = vector_slot (matches, j)) != NULL)
! 2175: for (k = 0; k < vector_active (match_vector); k++)
! 2176: {
! 2177: struct cmd_token *token = vector_slot (match_vector, k);
! 2178: vector_set (matchvec, token);
! 2179: }
! 2180:
! 2181: *status = CMD_SUCCESS;
! 2182: vector_set(matchvec, &token_cr);
! 2183: vector_free (cmd_vector);
! 2184: cmd_matches_free(&matches);
! 2185: cmd_describe_sort(matchvec);
! 2186: return matchvec;
! 2187: }
! 2188:
! 2189: ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
! 2190: if (ret == 1)
! 2191: {
! 2192: vector_free (cmd_vector);
! 2193: vector_free (matchvec);
! 2194: cmd_matches_free(&matches);
! 2195: *status = CMD_ERR_AMBIGUOUS;
! 2196: return NULL;
! 2197: }
! 2198: else if (ret == 2)
! 2199: {
! 2200: vector_free (cmd_vector);
! 2201: vector_free (matchvec);
! 2202: cmd_matches_free(&matches);
! 2203: *status = CMD_ERR_NO_MATCH;
! 2204: return NULL;
! 2205: }
! 2206: }
1.1 misho 2207:
2208: /* Make description vector. */
1.1.1.4 ! misho 2209: for (i = 0; i < vector_active (matches); i++)
! 2210: {
! 2211: if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
! 2212: {
! 2213: unsigned int j;
! 2214: vector vline_trimmed;
1.1 misho 2215:
1.1.1.4 ! misho 2216: command_found++;
! 2217: last_word = vector_slot(vline, vector_active(vline) - 1);
! 2218: if (last_word == NULL || !strlen(last_word))
! 2219: {
! 2220: vline_trimmed = vector_copy(vline);
! 2221: vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
1.1 misho 2222:
1.1.1.4 ! misho 2223: if (cmd_is_complete(cmd_element, vline_trimmed)
! 2224: && desc_unique_string(matchvec, command_cr))
! 2225: {
! 2226: if (match != vararg_match)
! 2227: vector_set(matchvec, &token_cr);
! 2228: }
! 2229:
! 2230: vector_free(vline_trimmed);
! 2231: }
! 2232:
! 2233: match_vector = vector_slot (matches, i);
! 2234: if (match_vector)
! 2235: {
! 2236: for (j = 0; j < vector_active(match_vector); j++)
! 2237: {
! 2238: struct cmd_token *token = vector_slot(match_vector, j);
! 2239: const char *string;
! 2240:
! 2241: string = cmd_entry_function_desc(command, token);
! 2242: if (string && desc_unique_string(matchvec, string))
! 2243: vector_set(matchvec, token);
! 2244: }
! 2245: }
! 2246: }
! 2247: }
! 2248:
! 2249: /*
! 2250: * We can get into this situation when the command is complete
! 2251: * but the last part of the command is an optional piece of
! 2252: * the cli.
! 2253: */
! 2254: last_word = vector_slot(vline, vector_active(vline) - 1);
! 2255: if (command_found == 0 && (last_word == NULL || !strlen(last_word)))
! 2256: vector_set(matchvec, &token_cr);
1.1 misho 2257:
2258: vector_free (cmd_vector);
1.1.1.4 ! misho 2259: cmd_matches_free(&matches);
1.1 misho 2260:
2261: if (vector_slot (matchvec, 0) == NULL)
2262: {
2263: vector_free (matchvec);
2264: *status = CMD_ERR_NO_MATCH;
2265: return NULL;
2266: }
2267:
2268: *status = CMD_SUCCESS;
1.1.1.4 ! misho 2269: cmd_describe_sort(matchvec);
1.1 misho 2270: return matchvec;
2271: }
2272:
2273: vector
2274: cmd_describe_command (vector vline, struct vty *vty, int *status)
2275: {
2276: vector ret;
2277:
2278: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2279: {
2280: enum node_type onode;
2281: vector shifted_vline;
2282: unsigned int index;
2283:
2284: onode = vty->node;
2285: vty->node = ENABLE_NODE;
2286: /* We can try it on enable node, cos' the vty is authenticated */
2287:
2288: shifted_vline = vector_init (vector_count(vline));
2289: /* use memcpy? */
2290: for (index = 1; index < vector_active (vline); index++)
2291: {
2292: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2293: }
2294:
2295: ret = cmd_describe_command_real (shifted_vline, vty, status);
2296:
2297: vector_free(shifted_vline);
2298: vty->node = onode;
2299: return ret;
2300: }
2301:
2302:
2303: return cmd_describe_command_real (vline, vty, status);
2304: }
2305:
2306:
2307: /* Check LCD of matched command. */
2308: static int
2309: cmd_lcd (char **matched)
2310: {
2311: int i;
2312: int j;
2313: int lcd = -1;
2314: char *s1, *s2;
2315: char c1, c2;
2316:
2317: if (matched[0] == NULL || matched[1] == NULL)
2318: return 0;
2319:
2320: for (i = 1; matched[i] != NULL; i++)
2321: {
2322: s1 = matched[i - 1];
2323: s2 = matched[i];
2324:
2325: for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
2326: if (c1 != c2)
2327: break;
2328:
2329: if (lcd < 0)
2330: lcd = j;
2331: else
2332: {
2333: if (lcd > j)
2334: lcd = j;
2335: }
2336: }
2337: return lcd;
2338: }
2339:
1.1.1.4 ! misho 2340: static int
! 2341: cmd_complete_cmp(const void *a, const void *b)
! 2342: {
! 2343: const char *first = *(char * const *)a;
! 2344: const char *second = *(char * const *)b;
! 2345:
! 2346: if (!first)
! 2347: {
! 2348: if (!second)
! 2349: return 0;
! 2350: return 1;
! 2351: }
! 2352: if (!second)
! 2353: return -1;
! 2354:
! 2355: return strcmp(first, second);
! 2356: }
! 2357:
! 2358: static void
! 2359: cmd_complete_sort(vector matchvec)
! 2360: {
! 2361: qsort(matchvec->index, vector_active(matchvec),
! 2362: sizeof(void*), cmd_complete_cmp);
! 2363: }
! 2364:
1.1 misho 2365: /* Command line completion support. */
2366: static char **
1.1.1.4 ! misho 2367: cmd_complete_command_real (vector vline, struct vty *vty, int *status, int islib)
1.1 misho 2368: {
2369: unsigned int i;
2370: vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2371: #define INIT_MATCHVEC_SIZE 10
2372: vector matchvec;
2373: unsigned int index;
2374: char **match_str;
1.1.1.4 ! misho 2375: struct cmd_token *token;
1.1 misho 2376: char *command;
2377: int lcd;
1.1.1.4 ! misho 2378: vector matches = NULL;
! 2379: vector match_vector;
1.1 misho 2380:
2381: if (vector_active (vline) == 0)
2382: {
2383: vector_free (cmd_vector);
2384: *status = CMD_ERR_NO_MATCH;
2385: return NULL;
2386: }
2387: else
2388: index = vector_active (vline) - 1;
2389:
1.1.1.4 ! misho 2390: /* First, filter by command string */
! 2391: for (i = 0; i <= index; i++)
! 2392: {
! 2393: command = vector_slot (vline, i);
! 2394: enum match_type match;
! 2395: int ret;
! 2396:
! 2397: if (matches)
! 2398: cmd_matches_free(&matches);
! 2399:
! 2400: /* First try completion match, if there is exactly match return 1 */
! 2401: ret = cmd_vector_filter(cmd_vector,
! 2402: FILTER_RELAXED,
! 2403: vline, i,
! 2404: &match,
! 2405: &matches);
1.1 misho 2406:
1.1.1.4 ! misho 2407: if (ret != CMD_SUCCESS)
! 2408: {
! 2409: vector_free(cmd_vector);
! 2410: cmd_matches_free(&matches);
! 2411: *status = ret;
! 2412: return NULL;
! 2413: }
1.1 misho 2414:
1.1.1.4 ! misho 2415: /* Break here - the completion mustn't be checked to be non-ambiguous */
! 2416: if (i == index)
! 2417: break;
! 2418:
! 2419: /* If there is exact match then filter ambiguous match else check
! 2420: ambiguousness. */
! 2421: ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
! 2422: if (ret == 1)
! 2423: {
! 2424: vector_free (cmd_vector);
! 2425: cmd_matches_free(&matches);
! 2426: *status = CMD_ERR_AMBIGUOUS;
! 2427: return NULL;
! 2428: }
! 2429: /*
1.1 misho 2430: else if (ret == 2)
2431: {
2432: vector_free (cmd_vector);
1.1.1.4 ! misho 2433: cmd_matches_free(&matches);
1.1 misho 2434: *status = CMD_ERR_NO_MATCH;
2435: return NULL;
2436: }
2437: */
1.1.1.4 ! misho 2438: }
1.1 misho 2439:
2440: /* Prepare match vector. */
2441: matchvec = vector_init (INIT_MATCHVEC_SIZE);
2442:
1.1.1.4 ! misho 2443: /* Build the possible list of continuations into a list of completions */
! 2444: for (i = 0; i < vector_active (matches); i++)
! 2445: if ((match_vector = vector_slot (matches, i)))
1.1 misho 2446: {
2447: const char *string;
1.1.1.4 ! misho 2448: unsigned int j;
1.1 misho 2449:
1.1.1.4 ! misho 2450: for (j = 0; j < vector_active (match_vector); j++)
! 2451: if ((token = vector_slot (match_vector, j)))
! 2452: {
! 2453: string = cmd_entry_function (vector_slot (vline, index), token);
! 2454: if (string && cmd_unique_string (matchvec, string))
! 2455: vector_set (matchvec, (islib != 0 ?
! 2456: XSTRDUP (MTYPE_TMP, string) :
! 2457: strdup (string) /* rl freed */));
! 2458: }
1.1 misho 2459: }
2460:
2461: /* We don't need cmd_vector any more. */
2462: vector_free (cmd_vector);
1.1.1.4 ! misho 2463: cmd_matches_free(&matches);
1.1 misho 2464:
2465: /* No matched command */
2466: if (vector_slot (matchvec, 0) == NULL)
2467: {
2468: vector_free (matchvec);
2469:
2470: /* In case of 'command \t' pattern. Do you need '?' command at
2471: the end of the line. */
2472: if (vector_slot (vline, index) == '\0')
2473: *status = CMD_ERR_NOTHING_TODO;
2474: else
2475: *status = CMD_ERR_NO_MATCH;
2476: return NULL;
2477: }
2478:
2479: /* Only one matched */
2480: if (vector_slot (matchvec, 1) == NULL)
2481: {
2482: match_str = (char **) matchvec->index;
2483: vector_only_wrapper_free (matchvec);
2484: *status = CMD_COMPLETE_FULL_MATCH;
2485: return match_str;
2486: }
2487: /* Make it sure last element is NULL. */
2488: vector_set (matchvec, NULL);
2489:
2490: /* Check LCD of matched strings. */
2491: if (vector_slot (vline, index) != NULL)
2492: {
2493: lcd = cmd_lcd ((char **) matchvec->index);
2494:
2495: if (lcd)
2496: {
2497: int len = strlen (vector_slot (vline, index));
2498:
2499: if (len < lcd)
2500: {
2501: char *lcdstr;
2502:
1.1.1.4 ! misho 2503: lcdstr = (islib != 0 ?
! 2504: XMALLOC (MTYPE_TMP, lcd + 1) :
! 2505: malloc(lcd + 1));
1.1 misho 2506: memcpy (lcdstr, matchvec->index[0], lcd);
2507: lcdstr[lcd] = '\0';
2508:
2509: /* match_str = (char **) &lcdstr; */
2510:
2511: /* Free matchvec. */
2512: for (i = 0; i < vector_active (matchvec); i++)
1.1.1.4 ! misho 2513: {
! 2514: if (vector_slot (matchvec, i))
! 2515: {
! 2516: if (islib != 0)
! 2517: XFREE (MTYPE_TMP, vector_slot (matchvec, i));
! 2518: else
! 2519: free (vector_slot (matchvec, i));
! 2520: }
! 2521: }
1.1 misho 2522: vector_free (matchvec);
2523:
2524: /* Make new matchvec. */
2525: matchvec = vector_init (INIT_MATCHVEC_SIZE);
2526: vector_set (matchvec, lcdstr);
2527: match_str = (char **) matchvec->index;
2528: vector_only_wrapper_free (matchvec);
2529:
2530: *status = CMD_COMPLETE_MATCH;
2531: return match_str;
2532: }
2533: }
2534: }
2535:
2536: match_str = (char **) matchvec->index;
1.1.1.4 ! misho 2537: cmd_complete_sort(matchvec);
1.1 misho 2538: vector_only_wrapper_free (matchvec);
2539: *status = CMD_COMPLETE_LIST_MATCH;
2540: return match_str;
2541: }
2542:
2543: char **
1.1.1.4 ! misho 2544: cmd_complete_command_lib (vector vline, struct vty *vty, int *status, int islib)
1.1 misho 2545: {
2546: char **ret;
2547:
2548: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2549: {
2550: enum node_type onode;
2551: vector shifted_vline;
2552: unsigned int index;
2553:
2554: onode = vty->node;
2555: vty->node = ENABLE_NODE;
2556: /* We can try it on enable node, cos' the vty is authenticated */
2557:
2558: shifted_vline = vector_init (vector_count(vline));
2559: /* use memcpy? */
2560: for (index = 1; index < vector_active (vline); index++)
2561: {
2562: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2563: }
2564:
1.1.1.4 ! misho 2565: ret = cmd_complete_command_real (shifted_vline, vty, status, islib);
1.1 misho 2566:
2567: vector_free(shifted_vline);
2568: vty->node = onode;
2569: return ret;
2570: }
2571:
1.1.1.4 ! misho 2572: return cmd_complete_command_real (vline, vty, status, islib);
! 2573: }
1.1 misho 2574:
1.1.1.4 ! misho 2575: char **
! 2576: cmd_complete_command (vector vline, struct vty *vty, int *status)
! 2577: {
! 2578: return cmd_complete_command_lib (vline, vty, status, 0);
1.1 misho 2579: }
2580:
2581: /* return parent node */
2582: /* MUST eventually converge on CONFIG_NODE */
2583: enum node_type
2584: node_parent ( enum node_type node )
2585: {
2586: enum node_type ret;
2587:
2588: assert (node > CONFIG_NODE);
2589:
2590: switch (node)
2591: {
2592: case BGP_VPNV4_NODE:
1.1.1.4 ! misho 2593: case BGP_VPNV6_NODE:
! 2594: case BGP_ENCAP_NODE:
! 2595: case BGP_ENCAPV6_NODE:
1.1 misho 2596: case BGP_IPV4_NODE:
2597: case BGP_IPV4M_NODE:
2598: case BGP_IPV6_NODE:
2599: case BGP_IPV6M_NODE:
2600: ret = BGP_NODE;
2601: break;
2602: case KEYCHAIN_KEY_NODE:
2603: ret = KEYCHAIN_NODE;
2604: break;
2605: default:
2606: ret = CONFIG_NODE;
2607: }
2608:
2609: return ret;
2610: }
2611:
2612: /* Execute command by argument vline vector. */
2613: static int
1.1.1.4 ! misho 2614: cmd_execute_command_real (vector vline,
! 2615: enum filter_type filter,
! 2616: struct vty *vty,
1.1 misho 2617: struct cmd_element **cmd)
2618: {
2619: unsigned int i;
2620: unsigned int index;
2621: vector cmd_vector;
2622: struct cmd_element *cmd_element;
2623: struct cmd_element *matched_element;
2624: unsigned int matched_count, incomplete_count;
2625: int argc;
2626: const char *argv[CMD_ARGC_MAX];
2627: enum match_type match = 0;
2628: char *command;
1.1.1.4 ! misho 2629: int ret;
! 2630: vector matches;
1.1 misho 2631:
2632: /* Make copy of command elements. */
2633: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2634:
2635: for (index = 0; index < vector_active (vline); index++)
1.1.1.4 ! misho 2636: {
! 2637: command = vector_slot (vline, index);
! 2638: ret = cmd_vector_filter(cmd_vector,
! 2639: filter,
! 2640: vline, index,
! 2641: &match,
! 2642: &matches);
1.1 misho 2643:
1.1.1.4 ! misho 2644: if (ret != CMD_SUCCESS)
! 2645: {
! 2646: cmd_matches_free(&matches);
! 2647: return ret;
! 2648: }
1.1 misho 2649:
1.1.1.4 ! misho 2650: if (match == vararg_match)
! 2651: {
! 2652: cmd_matches_free(&matches);
1.1 misho 2653: break;
1.1.1.4 ! misho 2654: }
1.1 misho 2655:
1.1.1.4 ! misho 2656: ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
! 2657: cmd_matches_free(&matches);
! 2658:
! 2659: if (ret == 1)
! 2660: {
! 2661: vector_free(cmd_vector);
! 2662: return CMD_ERR_AMBIGUOUS;
! 2663: }
! 2664: else if (ret == 2)
! 2665: {
! 2666: vector_free(cmd_vector);
! 2667: return CMD_ERR_NO_MATCH;
! 2668: }
! 2669: }
1.1 misho 2670:
2671: /* Check matched count. */
2672: matched_element = NULL;
2673: matched_count = 0;
2674: incomplete_count = 0;
2675:
2676: for (i = 0; i < vector_active (cmd_vector); i++)
2677: if ((cmd_element = vector_slot (cmd_vector, i)))
2678: {
1.1.1.4 ! misho 2679: if (cmd_is_complete(cmd_element, vline))
1.1 misho 2680: {
2681: matched_element = cmd_element;
2682: matched_count++;
2683: }
2684: else
2685: {
2686: incomplete_count++;
2687: }
2688: }
2689:
2690: /* Finish of using cmd_vector. */
2691: vector_free (cmd_vector);
2692:
2693: /* To execute command, matched_count must be 1. */
2694: if (matched_count == 0)
2695: {
2696: if (incomplete_count)
2697: return CMD_ERR_INCOMPLETE;
2698: else
2699: return CMD_ERR_NO_MATCH;
2700: }
2701:
2702: if (matched_count > 1)
2703: return CMD_ERR_AMBIGUOUS;
2704:
1.1.1.4 ! misho 2705: ret = cmd_parse(matched_element, vline, &argc, argv);
! 2706: if (ret != CMD_SUCCESS)
! 2707: return ret;
1.1 misho 2708:
2709: /* For vtysh execution. */
2710: if (cmd)
2711: *cmd = matched_element;
2712:
2713: if (matched_element->daemon)
2714: return CMD_SUCCESS_DAEMON;
2715:
2716: /* Execute matched command. */
2717: return (*matched_element->func) (matched_element, vty, argc, argv);
2718: }
2719:
1.1.1.4 ! misho 2720: /**
! 2721: * Execute a given command, handling things like "do ..." and checking
! 2722: * whether the given command might apply at a parent node if doesn't
! 2723: * apply for the current node.
! 2724: *
! 2725: * @param vline Command line input, vector of char* where each element is
! 2726: * one input token.
! 2727: * @param vty The vty context in which the command should be executed.
! 2728: * @param cmd Pointer where the struct cmd_element of the matched command
! 2729: * will be stored, if any. May be set to NULL if this info is
! 2730: * not needed.
! 2731: * @param vtysh If set != 0, don't lookup the command at parent nodes.
! 2732: * @return The status of the command that has been executed or an error code
! 2733: * as to why no command could be executed.
! 2734: */
1.1 misho 2735: int
2736: cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2737: int vtysh) {
2738: int ret, saved_ret, tried = 0;
2739: enum node_type onode, try_node;
2740:
2741: onode = try_node = vty->node;
2742:
2743: if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2744: {
2745: vector shifted_vline;
2746: unsigned int index;
2747:
2748: vty->node = ENABLE_NODE;
2749: /* We can try it on enable node, cos' the vty is authenticated */
2750:
2751: shifted_vline = vector_init (vector_count(vline));
2752: /* use memcpy? */
2753: for (index = 1; index < vector_active (vline); index++)
2754: {
2755: vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2756: }
2757:
1.1.1.4 ! misho 2758: ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
1.1 misho 2759:
2760: vector_free(shifted_vline);
2761: vty->node = onode;
2762: return ret;
2763: }
2764:
2765:
1.1.1.4 ! misho 2766: saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
1.1 misho 2767:
2768: if (vtysh)
2769: return saved_ret;
2770:
2771: /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2772: while ( ret != CMD_SUCCESS && ret != CMD_WARNING
2773: && vty->node > CONFIG_NODE )
2774: {
2775: try_node = node_parent(try_node);
2776: vty->node = try_node;
1.1.1.4 ! misho 2777: ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
1.1 misho 2778: tried = 1;
2779: if (ret == CMD_SUCCESS || ret == CMD_WARNING)
2780: {
2781: /* succesfull command, leave the node as is */
2782: return ret;
2783: }
2784: }
2785: /* no command succeeded, reset the vty to the original node and
2786: return the error for this node */
2787: if ( tried )
2788: vty->node = onode;
2789: return saved_ret;
2790: }
2791:
1.1.1.4 ! misho 2792: /**
! 2793: * Execute a given command, matching it strictly against the current node.
! 2794: * This mode is used when reading config files.
! 2795: *
! 2796: * @param vline Command line input, vector of char* where each element is
! 2797: * one input token.
! 2798: * @param vty The vty context in which the command should be executed.
! 2799: * @param cmd Pointer where the struct cmd_element* of the matched command
! 2800: * will be stored, if any. May be set to NULL if this info is
! 2801: * not needed.
! 2802: * @return The status of the command that has been executed or an error code
! 2803: * as to why no command could be executed.
! 2804: */
1.1 misho 2805: int
2806: cmd_execute_command_strict (vector vline, struct vty *vty,
2807: struct cmd_element **cmd)
2808: {
1.1.1.4 ! misho 2809: return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
! 2810: }
1.1 misho 2811:
1.1.1.4 ! misho 2812: /**
! 2813: * Parse one line of config, walking up the parse tree attempting to find a match
! 2814: *
! 2815: * @param vty The vty context in which the command should be executed.
! 2816: * @param cmd Pointer where the struct cmd_element* of the match command
! 2817: * will be stored, if any. May be set to NULL if this info is
! 2818: * not needed.
! 2819: * @param use_daemon Boolean to control whether or not we match on CMD_SUCCESS_DAEMON
! 2820: * or not.
! 2821: * @return The status of the command that has been executed or an error code
! 2822: * as to why no command could be executed.
! 2823: */
! 2824: int
! 2825: command_config_read_one_line (struct vty *vty, struct cmd_element **cmd, int use_daemon)
! 2826: {
! 2827: vector vline;
! 2828: int saved_node;
! 2829: int ret;
1.1 misho 2830:
1.1.1.4 ! misho 2831: vline = cmd_make_strvec (vty->buf);
1.1 misho 2832:
1.1.1.4 ! misho 2833: /* In case of comment line */
! 2834: if (vline == NULL)
! 2835: return CMD_SUCCESS;
1.1 misho 2836:
1.1.1.4 ! misho 2837: /* Execute configuration command : this is strict match */
! 2838: ret = cmd_execute_command_strict (vline, vty, cmd);
1.1 misho 2839:
1.1.1.4 ! misho 2840: saved_node = vty->node;
1.1 misho 2841:
1.1.1.4 ! misho 2842: while (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
! 2843: ret != CMD_SUCCESS && ret != CMD_WARNING &&
! 2844: ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE) {
! 2845: vty->node = node_parent(vty->node);
! 2846: ret = cmd_execute_command_strict (vline, vty, NULL);
! 2847: }
1.1 misho 2848:
1.1.1.4 ! misho 2849: // If climbing the tree did not work then ignore the command and
! 2850: // stay at the same node
! 2851: if (!(use_daemon && ret == CMD_SUCCESS_DAEMON) &&
! 2852: ret != CMD_SUCCESS && ret != CMD_WARNING &&
! 2853: ret != CMD_ERR_NOTHING_TODO)
1.1 misho 2854: {
1.1.1.4 ! misho 2855: vty->node = saved_node;
1.1 misho 2856: }
2857:
1.1.1.4 ! misho 2858: cmd_free_strvec (vline);
1.1 misho 2859:
1.1.1.4 ! misho 2860: return ret;
1.1 misho 2861: }
2862:
2863: /* Configration make from file. */
2864: int
1.1.1.4 ! misho 2865: config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
1.1 misho 2866: {
2867: int ret;
1.1.1.4 ! misho 2868: *line_num = 0;
1.1 misho 2869:
2870: while (fgets (vty->buf, VTY_BUFSIZ, fp))
2871: {
1.1.1.4 ! misho 2872: ++(*line_num);
1.1 misho 2873:
1.1.1.4 ! misho 2874: ret = command_config_read_one_line (vty, NULL, 0);
1.1 misho 2875:
2876: if (ret != CMD_SUCCESS && ret != CMD_WARNING
2877: && ret != CMD_ERR_NOTHING_TODO)
2878: return ret;
2879: }
2880: return CMD_SUCCESS;
2881: }
2882:
2883: /* Configration from terminal */
2884: DEFUN (config_terminal,
2885: config_terminal_cmd,
2886: "configure terminal",
2887: "Configuration from vty interface\n"
2888: "Configuration terminal\n")
2889: {
2890: if (vty_config_lock (vty))
2891: vty->node = CONFIG_NODE;
2892: else
2893: {
2894: vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2895: return CMD_WARNING;
2896: }
2897: return CMD_SUCCESS;
2898: }
2899:
2900: /* Enable command */
2901: DEFUN (enable,
2902: config_enable_cmd,
2903: "enable",
2904: "Turn on privileged mode command\n")
2905: {
2906: /* If enable password is NULL, change to ENABLE_NODE */
2907: if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2908: vty->type == VTY_SHELL_SERV)
2909: vty->node = ENABLE_NODE;
2910: else
2911: vty->node = AUTH_ENABLE_NODE;
2912:
2913: return CMD_SUCCESS;
2914: }
2915:
2916: /* Disable command */
2917: DEFUN (disable,
2918: config_disable_cmd,
2919: "disable",
2920: "Turn off privileged mode command\n")
2921: {
2922: if (vty->node == ENABLE_NODE)
2923: vty->node = VIEW_NODE;
2924: return CMD_SUCCESS;
2925: }
2926:
2927: /* Down vty node level. */
2928: DEFUN (config_exit,
2929: config_exit_cmd,
2930: "exit",
2931: "Exit current mode and down to previous mode\n")
2932: {
2933: switch (vty->node)
2934: {
2935: case VIEW_NODE:
2936: case ENABLE_NODE:
2937: case RESTRICTED_NODE:
2938: if (vty_shell (vty))
2939: exit (0);
2940: else
2941: vty->status = VTY_CLOSE;
2942: break;
2943: case CONFIG_NODE:
2944: vty->node = ENABLE_NODE;
2945: vty_config_unlock (vty);
2946: break;
2947: case INTERFACE_NODE:
2948: case ZEBRA_NODE:
2949: case BGP_NODE:
2950: case RIP_NODE:
2951: case RIPNG_NODE:
1.1.1.2 misho 2952: case BABEL_NODE:
1.1 misho 2953: case OSPF_NODE:
2954: case OSPF6_NODE:
2955: case ISIS_NODE:
2956: case KEYCHAIN_NODE:
2957: case MASC_NODE:
2958: case RMAP_NODE:
1.1.1.4 ! misho 2959: case PIM_NODE:
1.1 misho 2960: case VTY_NODE:
2961: vty->node = CONFIG_NODE;
2962: break;
2963: case BGP_IPV4_NODE:
2964: case BGP_IPV4M_NODE:
1.1.1.4 ! misho 2965: case BGP_VPNV4_NODE:
! 2966: case BGP_VPNV6_NODE:
! 2967: case BGP_ENCAP_NODE:
! 2968: case BGP_ENCAPV6_NODE:
1.1 misho 2969: case BGP_IPV6_NODE:
2970: case BGP_IPV6M_NODE:
2971: vty->node = BGP_NODE;
2972: break;
2973: case KEYCHAIN_KEY_NODE:
2974: vty->node = KEYCHAIN_NODE;
2975: break;
2976: default:
2977: break;
2978: }
2979: return CMD_SUCCESS;
2980: }
2981:
2982: /* quit is alias of exit. */
2983: ALIAS (config_exit,
2984: config_quit_cmd,
2985: "quit",
2986: "Exit current mode and down to previous mode\n")
2987:
2988: /* End of configuration. */
2989: DEFUN (config_end,
2990: config_end_cmd,
2991: "end",
2992: "End current mode and change to enable mode.")
2993: {
2994: switch (vty->node)
2995: {
2996: case VIEW_NODE:
2997: case ENABLE_NODE:
2998: case RESTRICTED_NODE:
2999: /* Nothing to do. */
3000: break;
3001: case CONFIG_NODE:
3002: case INTERFACE_NODE:
3003: case ZEBRA_NODE:
3004: case RIP_NODE:
3005: case RIPNG_NODE:
1.1.1.2 misho 3006: case BABEL_NODE:
1.1 misho 3007: case BGP_NODE:
1.1.1.4 ! misho 3008: case BGP_ENCAP_NODE:
! 3009: case BGP_ENCAPV6_NODE:
1.1 misho 3010: case BGP_VPNV4_NODE:
1.1.1.4 ! misho 3011: case BGP_VPNV6_NODE:
1.1 misho 3012: case BGP_IPV4_NODE:
3013: case BGP_IPV4M_NODE:
3014: case BGP_IPV6_NODE:
3015: case BGP_IPV6M_NODE:
3016: case RMAP_NODE:
3017: case OSPF_NODE:
3018: case OSPF6_NODE:
3019: case ISIS_NODE:
3020: case KEYCHAIN_NODE:
3021: case KEYCHAIN_KEY_NODE:
3022: case MASC_NODE:
1.1.1.4 ! misho 3023: case PIM_NODE:
1.1 misho 3024: case VTY_NODE:
3025: vty_config_unlock (vty);
3026: vty->node = ENABLE_NODE;
3027: break;
3028: default:
3029: break;
3030: }
3031: return CMD_SUCCESS;
3032: }
3033:
3034: /* Show version. */
3035: DEFUN (show_version,
3036: show_version_cmd,
3037: "show version",
3038: SHOW_STR
3039: "Displays zebra version\n")
3040: {
3041: vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
3042: VTY_NEWLINE);
1.1.1.3 misho 3043: vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
1.1.1.4 ! misho 3044: vty_out (vty, "configured with:%s %s%s", VTY_NEWLINE,
! 3045: QUAGGA_CONFIG_ARGS, VTY_NEWLINE);
1.1 misho 3046:
3047: return CMD_SUCCESS;
3048: }
3049:
3050: /* Help display function for all node. */
3051: DEFUN (config_help,
3052: config_help_cmd,
3053: "help",
3054: "Description of the interactive help system\n")
3055: {
3056: vty_out (vty,
3057: "Quagga VTY provides advanced help feature. When you need help,%s\
3058: anytime at the command line please press '?'.%s\
3059: %s\
3060: If nothing matches, the help list will be empty and you must backup%s\
3061: until entering a '?' shows the available options.%s\
3062: Two styles of help are provided:%s\
3063: 1. Full help is available when you are ready to enter a%s\
3064: command argument (e.g. 'show ?') and describes each possible%s\
3065: argument.%s\
3066: 2. Partial help is provided when an abbreviated argument is entered%s\
3067: and you want to know what arguments match the input%s\
3068: (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3069: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3070: VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
3071: return CMD_SUCCESS;
3072: }
3073:
3074: /* Help display function for all node. */
3075: DEFUN (config_list,
3076: config_list_cmd,
3077: "list",
3078: "Print command list\n")
3079: {
3080: unsigned int i;
3081: struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
3082: struct cmd_element *cmd;
3083:
3084: for (i = 0; i < vector_active (cnode->cmd_vector); i++)
3085: if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
3086: && !(cmd->attr == CMD_ATTR_DEPRECATED
3087: || cmd->attr == CMD_ATTR_HIDDEN))
3088: vty_out (vty, " %s%s", cmd->string,
3089: VTY_NEWLINE);
3090: return CMD_SUCCESS;
3091: }
3092:
3093: /* Write current configuration into file. */
3094: DEFUN (config_write_file,
3095: config_write_file_cmd,
3096: "write file",
3097: "Write running configuration to memory, network, or terminal\n"
3098: "Write to configuration file\n")
3099: {
3100: unsigned int i;
3101: int fd;
3102: struct cmd_node *node;
3103: char *config_file;
3104: char *config_file_tmp = NULL;
3105: char *config_file_sav = NULL;
3106: int ret = CMD_WARNING;
3107: struct vty *file_vty;
3108:
3109: /* Check and see if we are operating under vtysh configuration */
3110: if (host.config == NULL)
3111: {
3112: vty_out (vty, "Can't save to configuration file, using vtysh.%s",
3113: VTY_NEWLINE);
3114: return CMD_WARNING;
3115: }
3116:
3117: /* Get filename. */
3118: config_file = host.config;
3119:
3120: config_file_sav =
3121: XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
3122: strcpy (config_file_sav, config_file);
3123: strcat (config_file_sav, CONF_BACKUP_EXT);
3124:
3125:
3126: config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
3127: sprintf (config_file_tmp, "%s.XXXXXX", config_file);
3128:
3129: /* Open file to configuration write. */
3130: fd = mkstemp (config_file_tmp);
3131: if (fd < 0)
3132: {
3133: vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
3134: VTY_NEWLINE);
3135: goto finished;
3136: }
3137:
3138: /* Make vty for configuration file. */
3139: file_vty = vty_new ();
1.1.1.4 ! misho 3140: file_vty->wfd = fd;
1.1 misho 3141: file_vty->type = VTY_FILE;
3142:
3143: /* Config file header print. */
3144: vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
3145: vty_time_print (file_vty, 1);
3146: vty_out (file_vty, "!\n");
3147:
3148: for (i = 0; i < vector_active (cmdvec); i++)
3149: if ((node = vector_slot (cmdvec, i)) && node->func)
3150: {
3151: if ((*node->func) (file_vty))
3152: vty_out (file_vty, "!\n");
3153: }
3154: vty_close (file_vty);
3155:
3156: if (unlink (config_file_sav) != 0)
3157: if (errno != ENOENT)
3158: {
3159: vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
3160: VTY_NEWLINE);
3161: goto finished;
3162: }
3163: if (link (config_file, config_file_sav) != 0)
3164: {
3165: vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
3166: VTY_NEWLINE);
3167: goto finished;
3168: }
3169: sync ();
3170: if (unlink (config_file) != 0)
3171: {
3172: vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
3173: VTY_NEWLINE);
3174: goto finished;
3175: }
3176: if (link (config_file_tmp, config_file) != 0)
3177: {
3178: vty_out (vty, "Can't save configuration file %s.%s", config_file,
3179: VTY_NEWLINE);
3180: goto finished;
3181: }
3182: sync ();
3183:
3184: if (chmod (config_file, CONFIGFILE_MASK) != 0)
3185: {
3186: vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
3187: config_file, safe_strerror(errno), errno, VTY_NEWLINE);
3188: goto finished;
3189: }
3190:
3191: vty_out (vty, "Configuration saved to %s%s", config_file,
3192: VTY_NEWLINE);
3193: ret = CMD_SUCCESS;
3194:
3195: finished:
3196: unlink (config_file_tmp);
3197: XFREE (MTYPE_TMP, config_file_tmp);
3198: XFREE (MTYPE_TMP, config_file_sav);
3199: return ret;
3200: }
3201:
3202: ALIAS (config_write_file,
3203: config_write_cmd,
3204: "write",
3205: "Write running configuration to memory, network, or terminal\n")
3206:
3207: ALIAS (config_write_file,
3208: config_write_memory_cmd,
3209: "write memory",
3210: "Write running configuration to memory, network, or terminal\n"
3211: "Write configuration to the file (same as write file)\n")
3212:
3213: ALIAS (config_write_file,
3214: copy_runningconfig_startupconfig_cmd,
3215: "copy running-config startup-config",
3216: "Copy configuration\n"
3217: "Copy running config to... \n"
3218: "Copy running config to startup config (same as write file)\n")
3219:
3220: /* Write current configuration into the terminal. */
3221: DEFUN (config_write_terminal,
3222: config_write_terminal_cmd,
3223: "write terminal",
3224: "Write running configuration to memory, network, or terminal\n"
3225: "Write to terminal\n")
3226: {
3227: unsigned int i;
3228: struct cmd_node *node;
3229:
3230: if (vty->type == VTY_SHELL_SERV)
3231: {
3232: for (i = 0; i < vector_active (cmdvec); i++)
3233: if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
3234: {
3235: if ((*node->func) (vty))
3236: vty_out (vty, "!%s", VTY_NEWLINE);
3237: }
3238: }
3239: else
3240: {
3241: vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
3242: VTY_NEWLINE);
3243: vty_out (vty, "!%s", VTY_NEWLINE);
3244:
3245: for (i = 0; i < vector_active (cmdvec); i++)
3246: if ((node = vector_slot (cmdvec, i)) && node->func)
3247: {
3248: if ((*node->func) (vty))
3249: vty_out (vty, "!%s", VTY_NEWLINE);
3250: }
3251: vty_out (vty, "end%s",VTY_NEWLINE);
3252: }
3253: return CMD_SUCCESS;
3254: }
3255:
3256: /* Write current configuration into the terminal. */
3257: ALIAS (config_write_terminal,
3258: show_running_config_cmd,
3259: "show running-config",
3260: SHOW_STR
3261: "running configuration\n")
3262:
3263: /* Write startup configuration into the terminal. */
3264: DEFUN (show_startup_config,
3265: show_startup_config_cmd,
3266: "show startup-config",
3267: SHOW_STR
3268: "Contentes of startup configuration\n")
3269: {
3270: char buf[BUFSIZ];
3271: FILE *confp;
3272:
3273: confp = fopen (host.config, "r");
3274: if (confp == NULL)
3275: {
3276: vty_out (vty, "Can't open configuration file [%s]%s",
3277: host.config, VTY_NEWLINE);
3278: return CMD_WARNING;
3279: }
3280:
3281: while (fgets (buf, BUFSIZ, confp))
3282: {
3283: char *cp = buf;
3284:
3285: while (*cp != '\r' && *cp != '\n' && *cp != '\0')
3286: cp++;
3287: *cp = '\0';
3288:
3289: vty_out (vty, "%s%s", buf, VTY_NEWLINE);
3290: }
3291:
3292: fclose (confp);
3293:
3294: return CMD_SUCCESS;
3295: }
3296:
3297: /* Hostname configuration */
3298: DEFUN (config_hostname,
3299: hostname_cmd,
3300: "hostname WORD",
3301: "Set system's network name\n"
3302: "This system's network name\n")
3303: {
3304: if (!isalpha((int) *argv[0]))
3305: {
3306: vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
3307: return CMD_WARNING;
3308: }
3309:
3310: if (host.name)
3311: XFREE (MTYPE_HOST, host.name);
3312:
3313: host.name = XSTRDUP (MTYPE_HOST, argv[0]);
3314: return CMD_SUCCESS;
3315: }
3316:
3317: DEFUN (config_no_hostname,
3318: no_hostname_cmd,
3319: "no hostname [HOSTNAME]",
3320: NO_STR
3321: "Reset system's network name\n"
3322: "Host name of this router\n")
3323: {
3324: if (host.name)
3325: XFREE (MTYPE_HOST, host.name);
3326: host.name = NULL;
3327: return CMD_SUCCESS;
3328: }
3329:
3330: /* VTY interface password set. */
3331: DEFUN (config_password, password_cmd,
3332: "password (8|) WORD",
3333: "Assign the terminal connection password\n"
3334: "Specifies a HIDDEN password will follow\n"
3335: "dummy string \n"
3336: "The HIDDEN line password string\n")
3337: {
3338: /* Argument check. */
3339: if (argc == 0)
3340: {
3341: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3342: return CMD_WARNING;
3343: }
3344:
3345: if (argc == 2)
3346: {
3347: if (*argv[0] == '8')
3348: {
3349: if (host.password)
3350: XFREE (MTYPE_HOST, host.password);
3351: host.password = NULL;
3352: if (host.password_encrypt)
3353: XFREE (MTYPE_HOST, host.password_encrypt);
3354: host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3355: return CMD_SUCCESS;
3356: }
3357: else
3358: {
3359: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3360: return CMD_WARNING;
3361: }
3362: }
3363:
3364: if (!isalnum ((int) *argv[0]))
3365: {
3366: vty_out (vty,
3367: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3368: return CMD_WARNING;
3369: }
3370:
3371: if (host.password)
3372: XFREE (MTYPE_HOST, host.password);
3373: host.password = NULL;
3374:
3375: if (host.encrypt)
3376: {
3377: if (host.password_encrypt)
3378: XFREE (MTYPE_HOST, host.password_encrypt);
3379: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3380: }
3381: else
3382: host.password = XSTRDUP (MTYPE_HOST, argv[0]);
3383:
3384: return CMD_SUCCESS;
3385: }
3386:
3387: ALIAS (config_password, password_text_cmd,
3388: "password LINE",
3389: "Assign the terminal connection password\n"
3390: "The UNENCRYPTED (cleartext) line password\n")
3391:
3392: /* VTY enable password set. */
3393: DEFUN (config_enable_password, enable_password_cmd,
3394: "enable password (8|) WORD",
3395: "Modify enable password parameters\n"
3396: "Assign the privileged level password\n"
3397: "Specifies a HIDDEN password will follow\n"
3398: "dummy string \n"
3399: "The HIDDEN 'enable' password string\n")
3400: {
3401: /* Argument check. */
3402: if (argc == 0)
3403: {
3404: vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3405: return CMD_WARNING;
3406: }
3407:
3408: /* Crypt type is specified. */
3409: if (argc == 2)
3410: {
3411: if (*argv[0] == '8')
3412: {
3413: if (host.enable)
3414: XFREE (MTYPE_HOST, host.enable);
3415: host.enable = NULL;
3416:
3417: if (host.enable_encrypt)
3418: XFREE (MTYPE_HOST, host.enable_encrypt);
3419: host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
3420:
3421: return CMD_SUCCESS;
3422: }
3423: else
3424: {
3425: vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3426: return CMD_WARNING;
3427: }
3428: }
3429:
3430: if (!isalnum ((int) *argv[0]))
3431: {
3432: vty_out (vty,
3433: "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3434: return CMD_WARNING;
3435: }
3436:
3437: if (host.enable)
3438: XFREE (MTYPE_HOST, host.enable);
3439: host.enable = NULL;
3440:
3441: /* Plain password input. */
3442: if (host.encrypt)
3443: {
3444: if (host.enable_encrypt)
3445: XFREE (MTYPE_HOST, host.enable_encrypt);
3446: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
3447: }
3448: else
3449: host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
3450:
3451: return CMD_SUCCESS;
3452: }
3453:
3454: ALIAS (config_enable_password,
3455: enable_password_text_cmd,
3456: "enable password LINE",
3457: "Modify enable password parameters\n"
3458: "Assign the privileged level password\n"
3459: "The UNENCRYPTED (cleartext) 'enable' password\n")
3460:
3461: /* VTY enable password delete. */
3462: DEFUN (no_config_enable_password, no_enable_password_cmd,
3463: "no enable password",
3464: NO_STR
3465: "Modify enable password parameters\n"
3466: "Assign the privileged level password\n")
3467: {
3468: if (host.enable)
3469: XFREE (MTYPE_HOST, host.enable);
3470: host.enable = NULL;
3471:
3472: if (host.enable_encrypt)
3473: XFREE (MTYPE_HOST, host.enable_encrypt);
3474: host.enable_encrypt = NULL;
3475:
3476: return CMD_SUCCESS;
3477: }
3478:
3479: DEFUN (service_password_encrypt,
3480: service_password_encrypt_cmd,
3481: "service password-encryption",
3482: "Set up miscellaneous service\n"
3483: "Enable encrypted passwords\n")
3484: {
3485: if (host.encrypt)
3486: return CMD_SUCCESS;
3487:
3488: host.encrypt = 1;
3489:
3490: if (host.password)
3491: {
3492: if (host.password_encrypt)
3493: XFREE (MTYPE_HOST, host.password_encrypt);
3494: host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
3495: }
3496: if (host.enable)
3497: {
3498: if (host.enable_encrypt)
3499: XFREE (MTYPE_HOST, host.enable_encrypt);
3500: host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
3501: }
3502:
3503: return CMD_SUCCESS;
3504: }
3505:
3506: DEFUN (no_service_password_encrypt,
3507: no_service_password_encrypt_cmd,
3508: "no service password-encryption",
3509: NO_STR
3510: "Set up miscellaneous service\n"
3511: "Enable encrypted passwords\n")
3512: {
3513: if (! host.encrypt)
3514: return CMD_SUCCESS;
3515:
3516: host.encrypt = 0;
3517:
3518: if (host.password_encrypt)
3519: XFREE (MTYPE_HOST, host.password_encrypt);
3520: host.password_encrypt = NULL;
3521:
3522: if (host.enable_encrypt)
3523: XFREE (MTYPE_HOST, host.enable_encrypt);
3524: host.enable_encrypt = NULL;
3525:
3526: return CMD_SUCCESS;
3527: }
3528:
3529: DEFUN (config_terminal_length, config_terminal_length_cmd,
3530: "terminal length <0-512>",
3531: "Set terminal line parameters\n"
3532: "Set number of lines on a screen\n"
3533: "Number of lines on screen (0 for no pausing)\n")
3534: {
3535: int lines;
3536: char *endptr = NULL;
3537:
3538: lines = strtol (argv[0], &endptr, 10);
3539: if (lines < 0 || lines > 512 || *endptr != '\0')
3540: {
3541: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3542: return CMD_WARNING;
3543: }
3544: vty->lines = lines;
3545:
3546: return CMD_SUCCESS;
3547: }
3548:
3549: DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
3550: "terminal no length",
3551: "Set terminal line parameters\n"
3552: NO_STR
3553: "Set number of lines on a screen\n")
3554: {
3555: vty->lines = -1;
3556: return CMD_SUCCESS;
3557: }
3558:
3559: DEFUN (service_terminal_length, service_terminal_length_cmd,
3560: "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")
3564: {
3565: int lines;
3566: char *endptr = NULL;
3567:
3568: lines = strtol (argv[0], &endptr, 10);
3569: if (lines < 0 || lines > 512 || *endptr != '\0')
3570: {
3571: vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3572: return CMD_WARNING;
3573: }
3574: host.lines = lines;
3575:
3576: return CMD_SUCCESS;
3577: }
3578:
3579: DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3580: "no service terminal-length [<0-512>]",
3581: NO_STR
3582: "Set up miscellaneous service\n"
3583: "System wide terminal length configuration\n"
3584: "Number of lines of VTY (0 means no line control)\n")
3585: {
3586: host.lines = -1;
3587: return CMD_SUCCESS;
3588: }
3589:
3590: DEFUN_HIDDEN (do_echo,
3591: echo_cmd,
3592: "echo .MESSAGE",
3593: "Echo a message back to the vty\n"
3594: "The message to echo\n")
3595: {
3596: char *message;
3597:
3598: vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3599: VTY_NEWLINE);
3600: if (message)
3601: XFREE(MTYPE_TMP, message);
3602: return CMD_SUCCESS;
3603: }
3604:
3605: DEFUN (config_logmsg,
3606: config_logmsg_cmd,
3607: "logmsg "LOG_LEVELS" .MESSAGE",
3608: "Send a message to enabled logging destinations\n"
3609: LOG_LEVEL_DESC
3610: "The message to send\n")
3611: {
3612: int level;
3613: char *message;
3614:
3615: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3616: return CMD_ERR_NO_MATCH;
3617:
3618: zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
3619: if (message)
3620: XFREE(MTYPE_TMP, message);
3621: return CMD_SUCCESS;
3622: }
3623:
3624: DEFUN (show_logging,
3625: show_logging_cmd,
3626: "show logging",
3627: SHOW_STR
3628: "Show current logging configuration\n")
3629: {
3630: struct zlog *zl = zlog_default;
3631:
3632: vty_out (vty, "Syslog logging: ");
3633: if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3634: vty_out (vty, "disabled");
3635: else
3636: vty_out (vty, "level %s, facility %s, ident %s",
3637: zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3638: facility_name(zl->facility), zl->ident);
3639: vty_out (vty, "%s", VTY_NEWLINE);
3640:
3641: vty_out (vty, "Stdout logging: ");
3642: if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3643: vty_out (vty, "disabled");
3644: else
3645: vty_out (vty, "level %s",
3646: zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3647: vty_out (vty, "%s", VTY_NEWLINE);
3648:
3649: vty_out (vty, "Monitor logging: ");
3650: if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3651: vty_out (vty, "disabled");
3652: else
3653: vty_out (vty, "level %s",
3654: zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3655: vty_out (vty, "%s", VTY_NEWLINE);
3656:
3657: vty_out (vty, "File logging: ");
3658: if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3659: !zl->fp)
3660: vty_out (vty, "disabled");
3661: else
3662: vty_out (vty, "level %s, filename %s",
3663: zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3664: zl->filename);
3665: vty_out (vty, "%s", VTY_NEWLINE);
3666:
3667: vty_out (vty, "Protocol name: %s%s",
3668: zlog_proto_names[zl->protocol], VTY_NEWLINE);
3669: vty_out (vty, "Record priority: %s%s",
3670: (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3671: vty_out (vty, "Timestamp precision: %d%s",
3672: zl->timestamp_precision, VTY_NEWLINE);
3673:
3674: return CMD_SUCCESS;
3675: }
3676:
3677: DEFUN (config_log_stdout,
3678: config_log_stdout_cmd,
3679: "log stdout",
3680: "Logging control\n"
3681: "Set stdout logging level\n")
3682: {
3683: zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3684: return CMD_SUCCESS;
3685: }
3686:
3687: DEFUN (config_log_stdout_level,
3688: config_log_stdout_level_cmd,
3689: "log stdout "LOG_LEVELS,
3690: "Logging control\n"
3691: "Set stdout logging level\n"
3692: LOG_LEVEL_DESC)
3693: {
3694: int level;
3695:
3696: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3697: return CMD_ERR_NO_MATCH;
3698: zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3699: return CMD_SUCCESS;
3700: }
3701:
3702: DEFUN (no_config_log_stdout,
3703: no_config_log_stdout_cmd,
3704: "no log stdout [LEVEL]",
3705: NO_STR
3706: "Logging control\n"
3707: "Cancel logging to stdout\n"
3708: "Logging level\n")
3709: {
3710: zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3711: return CMD_SUCCESS;
3712: }
3713:
3714: DEFUN (config_log_monitor,
3715: config_log_monitor_cmd,
3716: "log monitor",
3717: "Logging control\n"
3718: "Set terminal line (monitor) logging level\n")
3719: {
3720: zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3721: return CMD_SUCCESS;
3722: }
3723:
3724: DEFUN (config_log_monitor_level,
3725: config_log_monitor_level_cmd,
3726: "log monitor "LOG_LEVELS,
3727: "Logging control\n"
3728: "Set terminal line (monitor) logging level\n"
3729: LOG_LEVEL_DESC)
3730: {
3731: int level;
3732:
3733: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3734: return CMD_ERR_NO_MATCH;
3735: zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3736: return CMD_SUCCESS;
3737: }
3738:
3739: DEFUN (no_config_log_monitor,
3740: no_config_log_monitor_cmd,
3741: "no log monitor [LEVEL]",
3742: NO_STR
3743: "Logging control\n"
3744: "Disable terminal line (monitor) logging\n"
3745: "Logging level\n")
3746: {
3747: zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3748: return CMD_SUCCESS;
3749: }
3750:
3751: static int
3752: set_log_file(struct vty *vty, const char *fname, int loglevel)
3753: {
3754: int ret;
3755: char *p = NULL;
3756: const char *fullpath;
3757:
3758: /* Path detection. */
3759: if (! IS_DIRECTORY_SEP (*fname))
3760: {
3761: char cwd[MAXPATHLEN+1];
3762: cwd[MAXPATHLEN] = '\0';
3763:
3764: if (getcwd (cwd, MAXPATHLEN) == NULL)
3765: {
3766: zlog_err ("config_log_file: Unable to alloc mem!");
3767: return CMD_WARNING;
3768: }
3769:
3770: if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3771: == NULL)
3772: {
3773: zlog_err ("config_log_file: Unable to alloc mem!");
3774: return CMD_WARNING;
3775: }
3776: sprintf (p, "%s/%s", cwd, fname);
3777: fullpath = p;
3778: }
3779: else
3780: fullpath = fname;
3781:
3782: ret = zlog_set_file (NULL, fullpath, loglevel);
3783:
3784: if (p)
3785: XFREE (MTYPE_TMP, p);
3786:
3787: if (!ret)
3788: {
3789: vty_out (vty, "can't open logfile %s\n", fname);
3790: return CMD_WARNING;
3791: }
3792:
3793: if (host.logfile)
3794: XFREE (MTYPE_HOST, host.logfile);
3795:
3796: host.logfile = XSTRDUP (MTYPE_HOST, fname);
3797:
3798: return CMD_SUCCESS;
3799: }
3800:
3801: DEFUN (config_log_file,
3802: config_log_file_cmd,
3803: "log file FILENAME",
3804: "Logging control\n"
3805: "Logging to file\n"
3806: "Logging filename\n")
3807: {
3808: return set_log_file(vty, argv[0], zlog_default->default_lvl);
3809: }
3810:
3811: DEFUN (config_log_file_level,
3812: config_log_file_level_cmd,
3813: "log file FILENAME "LOG_LEVELS,
3814: "Logging control\n"
3815: "Logging to file\n"
3816: "Logging filename\n"
3817: LOG_LEVEL_DESC)
3818: {
3819: int level;
3820:
3821: if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3822: return CMD_ERR_NO_MATCH;
3823: return set_log_file(vty, argv[0], level);
3824: }
3825:
3826: DEFUN (no_config_log_file,
3827: no_config_log_file_cmd,
3828: "no log file [FILENAME]",
3829: NO_STR
3830: "Logging control\n"
3831: "Cancel logging to file\n"
3832: "Logging file name\n")
3833: {
3834: zlog_reset_file (NULL);
3835:
3836: if (host.logfile)
3837: XFREE (MTYPE_HOST, host.logfile);
3838:
3839: host.logfile = NULL;
3840:
3841: return CMD_SUCCESS;
3842: }
3843:
3844: ALIAS (no_config_log_file,
3845: no_config_log_file_level_cmd,
3846: "no log file FILENAME LEVEL",
3847: NO_STR
3848: "Logging control\n"
3849: "Cancel logging to file\n"
3850: "Logging file name\n"
3851: "Logging level\n")
3852:
3853: DEFUN (config_log_syslog,
3854: config_log_syslog_cmd,
3855: "log syslog",
3856: "Logging control\n"
3857: "Set syslog logging level\n")
3858: {
3859: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3860: return CMD_SUCCESS;
3861: }
3862:
3863: DEFUN (config_log_syslog_level,
3864: config_log_syslog_level_cmd,
3865: "log syslog "LOG_LEVELS,
3866: "Logging control\n"
3867: "Set syslog logging level\n"
3868: LOG_LEVEL_DESC)
3869: {
3870: int level;
3871:
3872: if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3873: return CMD_ERR_NO_MATCH;
3874: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3875: return CMD_SUCCESS;
3876: }
3877:
3878: DEFUN_DEPRECATED (config_log_syslog_facility,
3879: config_log_syslog_facility_cmd,
3880: "log syslog facility "LOG_FACILITIES,
3881: "Logging control\n"
3882: "Logging goes to syslog\n"
3883: "(Deprecated) Facility parameter for syslog messages\n"
3884: LOG_FACILITY_DESC)
3885: {
3886: int facility;
3887:
3888: if ((facility = facility_match(argv[0])) < 0)
3889: return CMD_ERR_NO_MATCH;
3890:
3891: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3892: zlog_default->facility = facility;
3893: return CMD_SUCCESS;
3894: }
3895:
3896: DEFUN (no_config_log_syslog,
3897: no_config_log_syslog_cmd,
3898: "no log syslog [LEVEL]",
3899: NO_STR
3900: "Logging control\n"
3901: "Cancel logging to syslog\n"
3902: "Logging level\n")
3903: {
3904: zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3905: return CMD_SUCCESS;
3906: }
3907:
3908: ALIAS (no_config_log_syslog,
3909: no_config_log_syslog_facility_cmd,
3910: "no log syslog facility "LOG_FACILITIES,
3911: NO_STR
3912: "Logging control\n"
3913: "Logging goes to syslog\n"
3914: "Facility parameter for syslog messages\n"
3915: LOG_FACILITY_DESC)
3916:
3917: DEFUN (config_log_facility,
3918: config_log_facility_cmd,
3919: "log facility "LOG_FACILITIES,
3920: "Logging control\n"
3921: "Facility parameter for syslog messages\n"
3922: LOG_FACILITY_DESC)
3923: {
3924: int facility;
3925:
3926: if ((facility = facility_match(argv[0])) < 0)
3927: return CMD_ERR_NO_MATCH;
3928: zlog_default->facility = facility;
3929: return CMD_SUCCESS;
3930: }
3931:
3932: DEFUN (no_config_log_facility,
3933: no_config_log_facility_cmd,
3934: "no log facility [FACILITY]",
3935: NO_STR
3936: "Logging control\n"
3937: "Reset syslog facility to default (daemon)\n"
3938: "Syslog facility\n")
3939: {
3940: zlog_default->facility = LOG_DAEMON;
3941: return CMD_SUCCESS;
3942: }
3943:
3944: DEFUN_DEPRECATED (config_log_trap,
3945: config_log_trap_cmd,
3946: "log trap "LOG_LEVELS,
3947: "Logging control\n"
3948: "(Deprecated) Set logging level and default for all destinations\n"
3949: LOG_LEVEL_DESC)
3950: {
3951: int new_level ;
3952: int i;
3953:
3954: if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3955: return CMD_ERR_NO_MATCH;
3956:
3957: zlog_default->default_lvl = new_level;
3958: for (i = 0; i < ZLOG_NUM_DESTS; i++)
3959: if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3960: zlog_default->maxlvl[i] = new_level;
3961: return CMD_SUCCESS;
3962: }
3963:
3964: DEFUN_DEPRECATED (no_config_log_trap,
3965: no_config_log_trap_cmd,
3966: "no log trap [LEVEL]",
3967: NO_STR
3968: "Logging control\n"
3969: "Permit all logging information\n"
3970: "Logging level\n")
3971: {
3972: zlog_default->default_lvl = LOG_DEBUG;
3973: return CMD_SUCCESS;
3974: }
3975:
3976: DEFUN (config_log_record_priority,
3977: config_log_record_priority_cmd,
3978: "log record-priority",
3979: "Logging control\n"
3980: "Log the priority of the message within the message\n")
3981: {
3982: zlog_default->record_priority = 1 ;
3983: return CMD_SUCCESS;
3984: }
3985:
3986: DEFUN (no_config_log_record_priority,
3987: no_config_log_record_priority_cmd,
3988: "no log record-priority",
3989: NO_STR
3990: "Logging control\n"
3991: "Do not log the priority of the message within the message\n")
3992: {
3993: zlog_default->record_priority = 0 ;
3994: return CMD_SUCCESS;
3995: }
3996:
3997: DEFUN (config_log_timestamp_precision,
3998: config_log_timestamp_precision_cmd,
3999: "log timestamp precision <0-6>",
4000: "Logging control\n"
4001: "Timestamp configuration\n"
4002: "Set the timestamp precision\n"
4003: "Number of subsecond digits\n")
4004: {
4005: if (argc != 1)
4006: {
4007: vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
4008: return CMD_WARNING;
4009: }
4010:
4011: VTY_GET_INTEGER_RANGE("Timestamp Precision",
4012: zlog_default->timestamp_precision, argv[0], 0, 6);
4013: return CMD_SUCCESS;
4014: }
4015:
4016: DEFUN (no_config_log_timestamp_precision,
4017: no_config_log_timestamp_precision_cmd,
4018: "no log timestamp precision",
4019: NO_STR
4020: "Logging control\n"
4021: "Timestamp configuration\n"
4022: "Reset the timestamp precision to the default value of 0\n")
4023: {
4024: zlog_default->timestamp_precision = 0 ;
4025: return CMD_SUCCESS;
4026: }
4027:
4028: DEFUN (banner_motd_file,
4029: banner_motd_file_cmd,
4030: "banner motd file [FILE]",
4031: "Set banner\n"
4032: "Banner for motd\n"
4033: "Banner from a file\n"
4034: "Filename\n")
4035: {
4036: if (host.motdfile)
4037: XFREE (MTYPE_HOST, host.motdfile);
4038: host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
4039:
4040: return CMD_SUCCESS;
4041: }
4042:
4043: DEFUN (banner_motd_default,
4044: banner_motd_default_cmd,
4045: "banner motd default",
4046: "Set banner string\n"
4047: "Strings for motd\n"
4048: "Default string\n")
4049: {
4050: host.motd = default_motd;
4051: return CMD_SUCCESS;
4052: }
4053:
4054: DEFUN (no_banner_motd,
4055: no_banner_motd_cmd,
4056: "no banner motd",
4057: NO_STR
4058: "Set banner string\n"
4059: "Strings for motd\n")
4060: {
4061: host.motd = NULL;
4062: if (host.motdfile)
4063: XFREE (MTYPE_HOST, host.motdfile);
4064: host.motdfile = NULL;
4065: return CMD_SUCCESS;
4066: }
4067:
1.1.1.4 ! misho 4068: DEFUN (show_commandtree,
! 4069: show_commandtree_cmd,
! 4070: "show commandtree",
! 4071: NO_STR
! 4072: "Show command tree\n")
! 4073: {
! 4074: /* TBD */
! 4075: vector cmd_vector;
! 4076: unsigned int i;
! 4077:
! 4078: vty_out (vty, "Current node id: %d%s", vty->node, VTY_NEWLINE);
! 4079:
! 4080: /* vector of all commands installed at this node */
! 4081: cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
! 4082:
! 4083: /* loop over all commands at this node */
! 4084: for (i = 0; i < vector_active(cmd_vector); ++i)
! 4085: {
! 4086: struct cmd_element *cmd_element;
! 4087:
! 4088: /* A cmd_element (seems to be) is an individual command */
! 4089: if ((cmd_element = vector_slot (cmd_vector, i)) == NULL)
! 4090: continue;
! 4091:
! 4092: vty_out (vty, " %s%s", cmd_element->string, VTY_NEWLINE);
! 4093: }
! 4094:
! 4095: vector_free (cmd_vector);
! 4096: return CMD_SUCCESS;
! 4097: }
! 4098:
1.1 misho 4099: /* Set config filename. Called from vty.c */
4100: void
4101: host_config_set (char *filename)
4102: {
4103: if (host.config)
4104: XFREE (MTYPE_HOST, host.config);
4105: host.config = XSTRDUP (MTYPE_HOST, filename);
4106: }
4107:
4108: void
4109: install_default (enum node_type node)
4110: {
4111: install_element (node, &config_exit_cmd);
4112: install_element (node, &config_quit_cmd);
4113: install_element (node, &config_end_cmd);
4114: install_element (node, &config_help_cmd);
4115: install_element (node, &config_list_cmd);
4116:
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);
4122: }
4123:
4124: /* Initialize command interface. Install basic nodes and commands. */
4125: void
4126: cmd_init (int terminal)
4127: {
1.1.1.4 ! misho 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, "");
1.1 misho 4133:
4134: /* Allocate initial top vector of commands. */
4135: cmdvec = vector_init (VECTOR_MIN_SIZE);
4136:
4137: /* Default host value settings. */
4138: host.name = NULL;
4139: host.password = NULL;
4140: host.enable = NULL;
4141: host.logfile = NULL;
4142: host.config = NULL;
4143: host.lines = -1;
4144: host.motd = default_motd;
4145: host.motdfile = NULL;
4146:
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);
4154:
4155: /* Each node's basic commands. */
4156: install_element (VIEW_NODE, &show_version_cmd);
4157: if (terminal)
4158: {
4159: install_element (VIEW_NODE, &config_list_cmd);
4160: install_element (VIEW_NODE, &config_exit_cmd);
4161: install_element (VIEW_NODE, &config_quit_cmd);
4162: install_element (VIEW_NODE, &config_help_cmd);
4163: install_element (VIEW_NODE, &config_enable_cmd);
4164: install_element (VIEW_NODE, &config_terminal_length_cmd);
4165: install_element (VIEW_NODE, &config_terminal_no_length_cmd);
4166: install_element (VIEW_NODE, &show_logging_cmd);
1.1.1.4 ! misho 4167: install_element (VIEW_NODE, &show_commandtree_cmd);
1.1 misho 4168: install_element (VIEW_NODE, &echo_cmd);
4169:
4170: install_element (RESTRICTED_NODE, &config_list_cmd);
4171: install_element (RESTRICTED_NODE, &config_exit_cmd);
4172: install_element (RESTRICTED_NODE, &config_quit_cmd);
4173: install_element (RESTRICTED_NODE, &config_help_cmd);
4174: install_element (RESTRICTED_NODE, &config_enable_cmd);
4175: install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
4176: install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
1.1.1.4 ! misho 4177: install_element (RESTRICTED_NODE, &show_commandtree_cmd);
1.1 misho 4178: install_element (RESTRICTED_NODE, &echo_cmd);
4179: }
4180:
4181: if (terminal)
4182: {
4183: install_default (ENABLE_NODE);
4184: install_element (ENABLE_NODE, &config_disable_cmd);
4185: install_element (ENABLE_NODE, &config_terminal_cmd);
4186: install_element (ENABLE_NODE, ©_runningconfig_startupconfig_cmd);
4187: }
4188: install_element (ENABLE_NODE, &show_startup_config_cmd);
4189: install_element (ENABLE_NODE, &show_version_cmd);
1.1.1.4 ! misho 4190: install_element (ENABLE_NODE, &show_commandtree_cmd);
1.1 misho 4191:
4192: if (terminal)
4193: {
4194: install_element (ENABLE_NODE, &config_terminal_length_cmd);
4195: install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
4196: install_element (ENABLE_NODE, &show_logging_cmd);
4197: install_element (ENABLE_NODE, &echo_cmd);
4198: install_element (ENABLE_NODE, &config_logmsg_cmd);
4199:
4200: install_default (CONFIG_NODE);
4201: }
4202:
4203: install_element (CONFIG_NODE, &hostname_cmd);
4204: install_element (CONFIG_NODE, &no_hostname_cmd);
4205:
4206: if (terminal)
4207: {
4208: install_element (CONFIG_NODE, &password_cmd);
4209: install_element (CONFIG_NODE, &password_text_cmd);
4210: install_element (CONFIG_NODE, &enable_password_cmd);
4211: install_element (CONFIG_NODE, &enable_password_text_cmd);
4212: install_element (CONFIG_NODE, &no_enable_password_cmd);
4213:
4214: install_element (CONFIG_NODE, &config_log_stdout_cmd);
4215: install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
4216: install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
4217: install_element (CONFIG_NODE, &config_log_monitor_cmd);
4218: install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
4219: install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
4220: install_element (CONFIG_NODE, &config_log_file_cmd);
4221: install_element (CONFIG_NODE, &config_log_file_level_cmd);
4222: install_element (CONFIG_NODE, &no_config_log_file_cmd);
4223: install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
4224: install_element (CONFIG_NODE, &config_log_syslog_cmd);
4225: install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
4226: install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
4227: install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
4228: install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
4229: install_element (CONFIG_NODE, &config_log_facility_cmd);
4230: install_element (CONFIG_NODE, &no_config_log_facility_cmd);
4231: install_element (CONFIG_NODE, &config_log_trap_cmd);
4232: install_element (CONFIG_NODE, &no_config_log_trap_cmd);
4233: install_element (CONFIG_NODE, &config_log_record_priority_cmd);
4234: install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
4235: install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
4236: install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
4237: install_element (CONFIG_NODE, &service_password_encrypt_cmd);
4238: install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
4239: install_element (CONFIG_NODE, &banner_motd_default_cmd);
4240: install_element (CONFIG_NODE, &banner_motd_file_cmd);
4241: install_element (CONFIG_NODE, &no_banner_motd_cmd);
4242: install_element (CONFIG_NODE, &service_terminal_length_cmd);
4243: install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
4244:
4245: install_element (VIEW_NODE, &show_thread_cpu_cmd);
4246: install_element (ENABLE_NODE, &show_thread_cpu_cmd);
4247: install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
4248:
4249: install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
4250: install_element (VIEW_NODE, &show_work_queues_cmd);
4251: install_element (ENABLE_NODE, &show_work_queues_cmd);
4252: }
1.1.1.4 ! misho 4253: install_element (CONFIG_NODE, &show_commandtree_cmd);
! 4254: srandom(time(NULL));
! 4255: }
! 4256:
! 4257: static void
! 4258: cmd_terminate_token(struct cmd_token *token)
! 4259: {
! 4260: unsigned int i, j;
! 4261: vector keyword_vect;
! 4262:
! 4263: if (token->multiple)
! 4264: {
! 4265: for (i = 0; i < vector_active(token->multiple); i++)
! 4266: cmd_terminate_token(vector_slot(token->multiple, i));
! 4267: vector_free(token->multiple);
! 4268: token->multiple = NULL;
! 4269: }
! 4270:
! 4271: if (token->keyword)
! 4272: {
! 4273: for (i = 0; i < vector_active(token->keyword); i++)
! 4274: {
! 4275: keyword_vect = vector_slot(token->keyword, i);
! 4276: for (j = 0; j < vector_active(keyword_vect); j++)
! 4277: cmd_terminate_token(vector_slot(keyword_vect, j));
! 4278: vector_free(keyword_vect);
! 4279: }
! 4280: vector_free(token->keyword);
! 4281: token->keyword = NULL;
! 4282: }
! 4283:
! 4284: XFREE(MTYPE_CMD_TOKENS, token->cmd);
! 4285: XFREE(MTYPE_CMD_TOKENS, token->desc);
! 4286:
! 4287: XFREE(MTYPE_CMD_TOKENS, token);
! 4288: }
! 4289:
! 4290: static void
! 4291: cmd_terminate_element(struct cmd_element *cmd)
! 4292: {
! 4293: unsigned int i;
! 4294:
! 4295: if (cmd->tokens == NULL)
! 4296: return;
! 4297:
! 4298: for (i = 0; i < vector_active(cmd->tokens); i++)
! 4299: cmd_terminate_token(vector_slot(cmd->tokens, i));
! 4300:
! 4301: vector_free(cmd->tokens);
! 4302: cmd->tokens = NULL;
1.1 misho 4303: }
4304:
4305: void
4306: cmd_terminate ()
4307: {
1.1.1.4 ! misho 4308: unsigned int i, j;
1.1 misho 4309: struct cmd_node *cmd_node;
4310: struct cmd_element *cmd_element;
1.1.1.4 ! misho 4311: vector cmd_node_v;
1.1 misho 4312:
4313: if (cmdvec)
4314: {
4315: for (i = 0; i < vector_active (cmdvec); i++)
4316: if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
4317: {
4318: cmd_node_v = cmd_node->cmd_vector;
4319:
4320: for (j = 0; j < vector_active (cmd_node_v); j++)
1.1.1.4 ! misho 4321: if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
! 4322: cmd_terminate_element(cmd_element);
1.1 misho 4323:
4324: vector_free (cmd_node_v);
4325: }
4326:
4327: vector_free (cmdvec);
4328: cmdvec = NULL;
4329: }
4330:
4331: if (command_cr)
1.1.1.4 ! misho 4332: XFREE(MTYPE_CMD_TOKENS, command_cr);
! 4333: if (token_cr.desc)
! 4334: XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
1.1 misho 4335: if (host.name)
4336: XFREE (MTYPE_HOST, host.name);
4337: if (host.password)
4338: XFREE (MTYPE_HOST, host.password);
4339: if (host.password_encrypt)
4340: XFREE (MTYPE_HOST, host.password_encrypt);
4341: if (host.enable)
4342: XFREE (MTYPE_HOST, host.enable);
4343: if (host.enable_encrypt)
4344: XFREE (MTYPE_HOST, host.enable_encrypt);
4345: if (host.logfile)
4346: XFREE (MTYPE_HOST, host.logfile);
4347: if (host.motdfile)
4348: XFREE (MTYPE_HOST, host.motdfile);
4349: if (host.config)
4350: XFREE (MTYPE_HOST, host.config);
4351: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>