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