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