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