]> git.proxmox.com Git - mirror_frr.git/blame - lib/command.c
build: remove --disable-ipv6
[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:
12e41d03 2946 case PIM_NODE:
718e3744 2947 case VTY_NODE:
2948 vty->node = CONFIG_NODE;
2949 break;
2950 case BGP_VPNV4_NODE:
2951 case BGP_IPV4_NODE:
2952 case BGP_IPV4M_NODE:
2953 case BGP_IPV6_NODE:
1e836590 2954 case BGP_IPV6M_NODE:
718e3744 2955 vty->node = BGP_NODE;
2956 break;
2957 case KEYCHAIN_KEY_NODE:
2958 vty->node = KEYCHAIN_NODE;
2959 break;
2960 default:
2961 break;
2962 }
2963 return CMD_SUCCESS;
2964}
2965
2966/* quit is alias of exit. */
2967ALIAS (config_exit,
2968 config_quit_cmd,
2969 "quit",
2970 "Exit current mode and down to previous mode\n")
2971
2972/* End of configuration. */
2973DEFUN (config_end,
2974 config_end_cmd,
2975 "end",
2976 "End current mode and change to enable mode.")
2977{
2978 switch (vty->node)
2979 {
2980 case VIEW_NODE:
2981 case ENABLE_NODE:
62687ff1 2982 case RESTRICTED_NODE:
718e3744 2983 /* Nothing to do. */
2984 break;
2985 case CONFIG_NODE:
2986 case INTERFACE_NODE:
f93e3f69 2987 case VRF_NODE:
718e3744 2988 case ZEBRA_NODE:
2989 case RIP_NODE:
2990 case RIPNG_NODE:
2991 case BGP_NODE:
2992 case BGP_VPNV4_NODE:
2993 case BGP_IPV4_NODE:
2994 case BGP_IPV4M_NODE:
2995 case BGP_IPV6_NODE:
1e836590 2996 case BGP_IPV6M_NODE:
718e3744 2997 case RMAP_NODE:
2998 case OSPF_NODE:
2999 case OSPF6_NODE:
9e867fe6 3000 case ISIS_NODE:
718e3744 3001 case KEYCHAIN_NODE:
3002 case KEYCHAIN_KEY_NODE:
3003 case MASC_NODE:
12e41d03 3004 case PIM_NODE:
718e3744 3005 case VTY_NODE:
3006 vty_config_unlock (vty);
3007 vty->node = ENABLE_NODE;
3008 break;
3009 default:
3010 break;
3011 }
3012 return CMD_SUCCESS;
3013}
3014
3015/* Show version. */
3016DEFUN (show_version,
3017 show_version_cmd,
3018 "show version",
3019 SHOW_STR
3020 "Displays zebra version\n")
3021{
12f6ea23 3022 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
3023 VTY_NEWLINE);
0be793e6 3024 vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
718e3744 3025
3026 return CMD_SUCCESS;
3027}
3028
3029/* Help display function for all node. */
3030DEFUN (config_help,
3031 config_help_cmd,
3032 "help",
3033 "Description of the interactive help system\n")
3034{
3035 vty_out (vty,
6590f2c3 3036 "Quagga VTY provides advanced help feature. When you need help,%s\
718e3744 3037anytime at the command line please press '?'.%s\
3038%s\
3039If nothing matches, the help list will be empty and you must backup%s\
3040 until entering a '?' shows the available options.%s\
3041Two styles of help are provided:%s\
30421. Full help is available when you are ready to enter a%s\
3043command argument (e.g. 'show ?') and describes each possible%s\
3044argument.%s\
30452. Partial help is provided when an abbreviated argument is entered%s\
3046 and you want to know what arguments match the input%s\
3047 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3048 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
3049 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
3050 return CMD_SUCCESS;
3051}
3052
3053/* Help display function for all node. */
3054DEFUN (config_list,
3055 config_list_cmd,
3056 "list",
3057 "Print command list\n")
3058{
8c328f11 3059 unsigned int i;
718e3744 3060 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
3061 struct cmd_element *cmd;
3062
55468c86 3063 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
4275b1de 3064 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
3065 && !(cmd->attr == CMD_ATTR_DEPRECATED
3066 || cmd->attr == CMD_ATTR_HIDDEN))
718e3744 3067 vty_out (vty, " %s%s", cmd->string,
3068 VTY_NEWLINE);
3069 return CMD_SUCCESS;
3070}
3071
3072/* Write current configuration into file. */
3073DEFUN (config_write_file,
3074 config_write_file_cmd,
3075 "write file",
3076 "Write running configuration to memory, network, or terminal\n"
3077 "Write to configuration file\n")
3078{
8c328f11 3079 unsigned int i;
718e3744 3080 int fd;
3081 struct cmd_node *node;
3082 char *config_file;
3083 char *config_file_tmp = NULL;
3084 char *config_file_sav = NULL;
05865c90 3085 int ret = CMD_WARNING;
718e3744 3086 struct vty *file_vty;
e4421165 3087 struct stat conf_stat;
718e3744 3088
3089 /* Check and see if we are operating under vtysh configuration */
3090 if (host.config == NULL)
3091 {
3092 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
3093 VTY_NEWLINE);
3094 return CMD_WARNING;
3095 }
3096
3097 /* Get filename. */
3098 config_file = host.config;
3099
05865c90 3100 config_file_sav =
3101 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
718e3744 3102 strcpy (config_file_sav, config_file);
3103 strcat (config_file_sav, CONF_BACKUP_EXT);
3104
3105
05865c90 3106 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
718e3744 3107 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
3108
3109 /* Open file to configuration write. */
3110 fd = mkstemp (config_file_tmp);
3111 if (fd < 0)
3112 {
3113 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
3114 VTY_NEWLINE);
05865c90 3115 goto finished;
718e3744 3116 }
3117
3118 /* Make vty for configuration file. */
3119 file_vty = vty_new ();
3120 file_vty->fd = fd;
3121 file_vty->type = VTY_FILE;
3122
3123 /* Config file header print. */
3124 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
3125 vty_time_print (file_vty, 1);
3126 vty_out (file_vty, "!\n");
3127
55468c86 3128 for (i = 0; i < vector_active (cmdvec); i++)
718e3744 3129 if ((node = vector_slot (cmdvec, i)) && node->func)
3130 {
3131 if ((*node->func) (file_vty))
3132 vty_out (file_vty, "!\n");
3133 }
3134 vty_close (file_vty);
3135
e4421165 3136 if (stat(config_file, &conf_stat) >= 0)
718e3744 3137 {
e4421165
DS
3138 if (unlink (config_file_sav) != 0)
3139 if (errno != ENOENT)
3140 {
3141 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
3142 VTY_NEWLINE);
3143 goto finished;
3144 }
3145 if (link (config_file, config_file_sav) != 0)
3146 {
3147 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
3148 VTY_NEWLINE);
3149 goto finished;
3150 }
3151 sync ();
3152 if (unlink (config_file) != 0)
3153 {
3154 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
3155 VTY_NEWLINE);
3156 goto finished;
3157 }
718e3744 3158 }
3159 if (link (config_file_tmp, config_file) != 0)
3160 {
3161 vty_out (vty, "Can't save configuration file %s.%s", config_file,
3162 VTY_NEWLINE);
05865c90 3163 goto finished;
718e3744 3164 }
718e3744 3165 sync ();
3166
aa593d5e 3167 if (chmod (config_file, CONFIGFILE_MASK) != 0)
3168 {
3169 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
6099b3b5 3170 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
05865c90 3171 goto finished;
aa593d5e 3172 }
3173
718e3744 3174 vty_out (vty, "Configuration saved to %s%s", config_file,
3175 VTY_NEWLINE);
05865c90 3176 ret = CMD_SUCCESS;
3177
3178finished:
3179 unlink (config_file_tmp);
3180 XFREE (MTYPE_TMP, config_file_tmp);
3181 XFREE (MTYPE_TMP, config_file_sav);
3182 return ret;
718e3744 3183}
3184
3185ALIAS (config_write_file,
3186 config_write_cmd,
3187 "write",
3188 "Write running configuration to memory, network, or terminal\n")
3189
3190ALIAS (config_write_file,
3191 config_write_memory_cmd,
3192 "write memory",
3193 "Write running configuration to memory, network, or terminal\n"
3194 "Write configuration to the file (same as write file)\n")
3195
3196ALIAS (config_write_file,
3197 copy_runningconfig_startupconfig_cmd,
3198 "copy running-config startup-config",
3199 "Copy configuration\n"
3200 "Copy running config to... \n"
3201 "Copy running config to startup config (same as write file)\n")
3202
3203/* Write current configuration into the terminal. */
3204DEFUN (config_write_terminal,
3205 config_write_terminal_cmd,
3206 "write terminal",
3207 "Write running configuration to memory, network, or terminal\n"
3208 "Write to terminal\n")
3209{
8c328f11 3210 unsigned int i;
718e3744 3211 struct cmd_node *node;
3212
3213 if (vty->type == VTY_SHELL_SERV)
3214 {
55468c86 3215 for (i = 0; i < vector_active (cmdvec); i++)
718e3744 3216 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
3217 {
3218 if ((*node->func) (vty))
3219 vty_out (vty, "!%s", VTY_NEWLINE);
3220 }
3221 }
3222 else
3223 {
3224 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
3225 VTY_NEWLINE);
3226 vty_out (vty, "!%s", VTY_NEWLINE);
3227
55468c86 3228 for (i = 0; i < vector_active (cmdvec); i++)
718e3744 3229 if ((node = vector_slot (cmdvec, i)) && node->func)
3230 {
3231 if ((*node->func) (vty))
3232 vty_out (vty, "!%s", VTY_NEWLINE);
3233 }
3234 vty_out (vty, "end%s",VTY_NEWLINE);
3235 }
3236 return CMD_SUCCESS;
3237}
3238
3239/* Write current configuration into the terminal. */
3240ALIAS (config_write_terminal,
3241 show_running_config_cmd,
3242 "show running-config",
3243 SHOW_STR
3244 "running configuration\n")
3245
3246/* Write startup configuration into the terminal. */
3247DEFUN (show_startup_config,
3248 show_startup_config_cmd,
3249 "show startup-config",
3250 SHOW_STR
3251 "Contentes of startup configuration\n")
3252{
3253 char buf[BUFSIZ];
3254 FILE *confp;
3255
3256 confp = fopen (host.config, "r");
3257 if (confp == NULL)
3258 {
1db63918
DS
3259 vty_out (vty, "Can't open configuration file [%s] due to '%s'%s",
3260 host.config, safe_strerror(errno), VTY_NEWLINE);
718e3744 3261 return CMD_WARNING;
3262 }
3263
3264 while (fgets (buf, BUFSIZ, confp))
3265 {
3266 char *cp = buf;
3267
3268 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
3269 cp++;
3270 *cp = '\0';
3271
3272 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
3273 }
3274
3275 fclose (confp);
3276
3277 return CMD_SUCCESS;
3278}
3279
3280/* Hostname configuration */
3281DEFUN (config_hostname,
3282 hostname_cmd,
3283 "hostname WORD",
3284 "Set system's network name\n"
3285 "This system's network name\n")
3286{
3287 if (!isalpha((int) *argv[0]))
3288 {
3289 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
3290 return CMD_WARNING;
3291 }
3292
3293 if (host.name)
05865c90 3294 XFREE (MTYPE_HOST, host.name);
718e3744 3295
05865c90 3296 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
718e3744 3297 return CMD_SUCCESS;
3298}
3299
3300DEFUN (config_no_hostname,
3301 no_hostname_cmd,
3302 "no hostname [HOSTNAME]",
3303 NO_STR
3304 "Reset system's network name\n"
3305 "Host name of this router\n")
3306{
3307 if (host.name)
05865c90 3308 XFREE (MTYPE_HOST, host.name);
718e3744 3309 host.name = NULL;
3310 return CMD_SUCCESS;
3311}
3312
3313/* VTY interface password set. */
3314DEFUN (config_password, password_cmd,
3315 "password (8|) WORD",
3316 "Assign the terminal connection password\n"
3317 "Specifies a HIDDEN password will follow\n"
3318 "dummy string \n"
3319 "The HIDDEN line password string\n")
3320{
3321 /* Argument check. */
3322 if (argc == 0)
3323 {
3324 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3325 return CMD_WARNING;
3326 }
3327
3328 if (argc == 2)
3329 {
3330 if (*argv[0] == '8')
3331 {
3332 if (host.password)
05865c90 3333 XFREE (MTYPE_HOST, host.password);
718e3744 3334 host.password = NULL;
3335 if (host.password_encrypt)
05865c90 3336 XFREE (MTYPE_HOST, host.password_encrypt);
3337 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
718e3744 3338 return CMD_SUCCESS;
3339 }
3340 else
3341 {
3342 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3343 return CMD_WARNING;
3344 }
3345 }
3346
3347 if (!isalnum ((int) *argv[0]))
3348 {
3349 vty_out (vty,
3350 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3351 return CMD_WARNING;
3352 }
3353
3354 if (host.password)
05865c90 3355 XFREE (MTYPE_HOST, host.password);
718e3744 3356 host.password = NULL;
3357
3358 if (host.encrypt)
3359 {
3360 if (host.password_encrypt)
05865c90 3361 XFREE (MTYPE_HOST, host.password_encrypt);
3362 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
718e3744 3363 }
3364 else
05865c90 3365 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
718e3744 3366
3367 return CMD_SUCCESS;
3368}
3369
3370ALIAS (config_password, password_text_cmd,
3371 "password LINE",
3372 "Assign the terminal connection password\n"
3373 "The UNENCRYPTED (cleartext) line password\n")
3374
3375/* VTY enable password set. */
3376DEFUN (config_enable_password, enable_password_cmd,
3377 "enable password (8|) WORD",
3378 "Modify enable password parameters\n"
3379 "Assign the privileged level password\n"
3380 "Specifies a HIDDEN password will follow\n"
3381 "dummy string \n"
3382 "The HIDDEN 'enable' password string\n")
3383{
3384 /* Argument check. */
3385 if (argc == 0)
3386 {
3387 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3388 return CMD_WARNING;
3389 }
3390
3391 /* Crypt type is specified. */
3392 if (argc == 2)
3393 {
3394 if (*argv[0] == '8')
3395 {
3396 if (host.enable)
05865c90 3397 XFREE (MTYPE_HOST, host.enable);
718e3744 3398 host.enable = NULL;
3399
3400 if (host.enable_encrypt)
05865c90 3401 XFREE (MTYPE_HOST, host.enable_encrypt);
3402 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
718e3744 3403
3404 return CMD_SUCCESS;
3405 }
3406 else
3407 {
3408 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3409 return CMD_WARNING;
3410 }
3411 }
3412
3413 if (!isalnum ((int) *argv[0]))
3414 {
3415 vty_out (vty,
3416 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3417 return CMD_WARNING;
3418 }
3419
3420 if (host.enable)
05865c90 3421 XFREE (MTYPE_HOST, host.enable);
718e3744 3422 host.enable = NULL;
3423
3424 /* Plain password input. */
3425 if (host.encrypt)
3426 {
3427 if (host.enable_encrypt)
05865c90 3428 XFREE (MTYPE_HOST, host.enable_encrypt);
3429 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
718e3744 3430 }
3431 else
05865c90 3432 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
718e3744 3433
3434 return CMD_SUCCESS;
3435}
3436
3437ALIAS (config_enable_password,
3438 enable_password_text_cmd,
3439 "enable password LINE",
3440 "Modify enable password parameters\n"
3441 "Assign the privileged level password\n"
3442 "The UNENCRYPTED (cleartext) 'enable' password\n")
3443
3444/* VTY enable password delete. */
3445DEFUN (no_config_enable_password, no_enable_password_cmd,
3446 "no enable password",
3447 NO_STR
3448 "Modify enable password parameters\n"
3449 "Assign the privileged level password\n")
3450{
3451 if (host.enable)
05865c90 3452 XFREE (MTYPE_HOST, host.enable);
718e3744 3453 host.enable = NULL;
3454
3455 if (host.enable_encrypt)
05865c90 3456 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 3457 host.enable_encrypt = NULL;
3458
3459 return CMD_SUCCESS;
3460}
3461
3462DEFUN (service_password_encrypt,
3463 service_password_encrypt_cmd,
3464 "service password-encryption",
3465 "Set up miscellaneous service\n"
3466 "Enable encrypted passwords\n")
3467{
3468 if (host.encrypt)
3469 return CMD_SUCCESS;
3470
3471 host.encrypt = 1;
3472
3473 if (host.password)
3474 {
3475 if (host.password_encrypt)
05865c90 3476 XFREE (MTYPE_HOST, host.password_encrypt);
3477 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
718e3744 3478 }
3479 if (host.enable)
3480 {
3481 if (host.enable_encrypt)
05865c90 3482 XFREE (MTYPE_HOST, host.enable_encrypt);
3483 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
718e3744 3484 }
3485
3486 return CMD_SUCCESS;
3487}
3488
3489DEFUN (no_service_password_encrypt,
3490 no_service_password_encrypt_cmd,
3491 "no service password-encryption",
3492 NO_STR
3493 "Set up miscellaneous service\n"
3494 "Enable encrypted passwords\n")
3495{
3496 if (! host.encrypt)
3497 return CMD_SUCCESS;
3498
3499 host.encrypt = 0;
3500
3501 if (host.password_encrypt)
05865c90 3502 XFREE (MTYPE_HOST, host.password_encrypt);
718e3744 3503 host.password_encrypt = NULL;
3504
3505 if (host.enable_encrypt)
05865c90 3506 XFREE (MTYPE_HOST, host.enable_encrypt);
718e3744 3507 host.enable_encrypt = NULL;
3508
3509 return CMD_SUCCESS;
3510}
3511
3512DEFUN (config_terminal_length, config_terminal_length_cmd,
3513 "terminal length <0-512>",
3514 "Set terminal line parameters\n"
3515 "Set number of lines on a screen\n"
3516 "Number of lines on screen (0 for no pausing)\n")
3517{
3518 int lines;
3519 char *endptr = NULL;
3520
3521 lines = strtol (argv[0], &endptr, 10);
3522 if (lines < 0 || lines > 512 || *endptr != '\0')
3523 {
3524 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3525 return CMD_WARNING;
3526 }
3527 vty->lines = lines;
3528
3529 return CMD_SUCCESS;
3530}
3531
3532DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
3533 "terminal no length",
3534 "Set terminal line parameters\n"
3535 NO_STR
3536 "Set number of lines on a screen\n")
3537{
3538 vty->lines = -1;
3539 return CMD_SUCCESS;
3540}
3541
3542DEFUN (service_terminal_length, service_terminal_length_cmd,
3543 "service terminal-length <0-512>",
3544 "Set up miscellaneous service\n"
3545 "System wide terminal length configuration\n"
3546 "Number of lines of VTY (0 means no line control)\n")
3547{
3548 int lines;
3549 char *endptr = NULL;
3550
3551 lines = strtol (argv[0], &endptr, 10);
3552 if (lines < 0 || lines > 512 || *endptr != '\0')
3553 {
3554 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3555 return CMD_WARNING;
3556 }
3557 host.lines = lines;
3558
3559 return CMD_SUCCESS;
3560}
3561
3562DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3563 "no service terminal-length [<0-512>]",
3564 NO_STR
3565 "Set up miscellaneous service\n"
3566 "System wide terminal length configuration\n"
3567 "Number of lines of VTY (0 means no line control)\n")
3568{
3569 host.lines = -1;
3570 return CMD_SUCCESS;
3571}
3572
2885f72d 3573DEFUN_HIDDEN (do_echo,
3574 echo_cmd,
3575 "echo .MESSAGE",
3576 "Echo a message back to the vty\n"
3577 "The message to echo\n")
3578{
3579 char *message;
3580
f6834d4c 3581 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3582 VTY_NEWLINE);
3583 if (message)
3584 XFREE(MTYPE_TMP, message);
2885f72d 3585 return CMD_SUCCESS;
3586}
3587
274a4a44 3588DEFUN (config_logmsg,
3589 config_logmsg_cmd,
3590 "logmsg "LOG_LEVELS" .MESSAGE",
3591 "Send a message to enabled logging destinations\n"
3592 LOG_LEVEL_DESC
3593 "The message to send\n")
3594{
3595 int level;
3596 char *message;
3597
3598 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3599 return CMD_ERR_NO_MATCH;
3600
fc95186c 3601 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
f6834d4c 3602 if (message)
3603 XFREE(MTYPE_TMP, message);
274a4a44 3604 return CMD_SUCCESS;
3605}
3606
3607DEFUN (show_logging,
3608 show_logging_cmd,
3609 "show logging",
3610 SHOW_STR
3611 "Show current logging configuration\n")
3612{
3613 struct zlog *zl = zlog_default;
3614
3615 vty_out (vty, "Syslog logging: ");
3616 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3617 vty_out (vty, "disabled");
3618 else
3619 vty_out (vty, "level %s, facility %s, ident %s",
3620 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3621 facility_name(zl->facility), zl->ident);
3622 vty_out (vty, "%s", VTY_NEWLINE);
3623
3624 vty_out (vty, "Stdout logging: ");
3625 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3626 vty_out (vty, "disabled");
3627 else
3628 vty_out (vty, "level %s",
3629 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3630 vty_out (vty, "%s", VTY_NEWLINE);
3631
3632 vty_out (vty, "Monitor logging: ");
3633 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3634 vty_out (vty, "disabled");
3635 else
3636 vty_out (vty, "level %s",
3637 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3638 vty_out (vty, "%s", VTY_NEWLINE);
3639
3640 vty_out (vty, "File logging: ");
3641 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3642 !zl->fp)
3643 vty_out (vty, "disabled");
3644 else
3645 vty_out (vty, "level %s, filename %s",
3646 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3647 zl->filename);
3648 vty_out (vty, "%s", VTY_NEWLINE);
3649
3650 vty_out (vty, "Protocol name: %s%s",
3651 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3652 vty_out (vty, "Record priority: %s%s",
3653 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
1ed72e0b
AS
3654 vty_out (vty, "Timestamp precision: %d%s",
3655 zl->timestamp_precision, VTY_NEWLINE);
274a4a44 3656
3657 return CMD_SUCCESS;
3658}
3659
718e3744 3660DEFUN (config_log_stdout,
3661 config_log_stdout_cmd,
3662 "log stdout",
3663 "Logging control\n"
274a4a44 3664 "Set stdout logging level\n")
718e3744 3665{
274a4a44 3666 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3667 return CMD_SUCCESS;
3668}
3669
3670DEFUN (config_log_stdout_level,
3671 config_log_stdout_level_cmd,
3672 "log stdout "LOG_LEVELS,
3673 "Logging control\n"
3674 "Set stdout logging level\n"
3675 LOG_LEVEL_DESC)
3676{
3677 int level;
3678
3679 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3680 return CMD_ERR_NO_MATCH;
3681 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
718e3744 3682 return CMD_SUCCESS;
3683}
3684
3685DEFUN (no_config_log_stdout,
3686 no_config_log_stdout_cmd,
274a4a44 3687 "no log stdout [LEVEL]",
718e3744 3688 NO_STR
3689 "Logging control\n"
274a4a44 3690 "Cancel logging to stdout\n"
3691 "Logging level\n")
718e3744 3692{
274a4a44 3693 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
718e3744 3694 return CMD_SUCCESS;
3695}
3696
274a4a44 3697DEFUN (config_log_monitor,
3698 config_log_monitor_cmd,
3699 "log monitor",
718e3744 3700 "Logging control\n"
274a4a44 3701 "Set terminal line (monitor) logging level\n")
3702{
3703 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3704 return CMD_SUCCESS;
3705}
3706
3707DEFUN (config_log_monitor_level,
3708 config_log_monitor_level_cmd,
3709 "log monitor "LOG_LEVELS,
3710 "Logging control\n"
3711 "Set terminal line (monitor) logging level\n"
3712 LOG_LEVEL_DESC)
3713{
3714 int level;
3715
3716 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3717 return CMD_ERR_NO_MATCH;
3718 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3719 return CMD_SUCCESS;
3720}
3721
3722DEFUN (no_config_log_monitor,
3723 no_config_log_monitor_cmd,
3724 "no log monitor [LEVEL]",
3725 NO_STR
3726 "Logging control\n"
3727 "Disable terminal line (monitor) logging\n"
3728 "Logging level\n")
3729{
3730 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3731 return CMD_SUCCESS;
3732}
3733
3734static int
3735set_log_file(struct vty *vty, const char *fname, int loglevel)
718e3744 3736{
3737 int ret;
9035efaa 3738 char *p = NULL;
3739 const char *fullpath;
3740
718e3744 3741 /* Path detection. */
274a4a44 3742 if (! IS_DIRECTORY_SEP (*fname))
718e3744 3743 {
9035efaa 3744 char cwd[MAXPATHLEN+1];
3745 cwd[MAXPATHLEN] = '\0';
3746
3747 if (getcwd (cwd, MAXPATHLEN) == NULL)
3748 {
3749 zlog_err ("config_log_file: Unable to alloc mem!");
3750 return CMD_WARNING;
3751 }
3752
274a4a44 3753 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
9035efaa 3754 == NULL)
3755 {
3756 zlog_err ("config_log_file: Unable to alloc mem!");
3757 return CMD_WARNING;
3758 }
274a4a44 3759 sprintf (p, "%s/%s", cwd, fname);
9035efaa 3760 fullpath = p;
718e3744 3761 }
3762 else
274a4a44 3763 fullpath = fname;
718e3744 3764
274a4a44 3765 ret = zlog_set_file (NULL, fullpath, loglevel);
718e3744 3766
9035efaa 3767 if (p)
3768 XFREE (MTYPE_TMP, p);
3769
718e3744 3770 if (!ret)
3771 {
274a4a44 3772 vty_out (vty, "can't open logfile %s\n", fname);
718e3744 3773 return CMD_WARNING;
3774 }
3775
3776 if (host.logfile)
05865c90 3777 XFREE (MTYPE_HOST, host.logfile);
718e3744 3778
05865c90 3779 host.logfile = XSTRDUP (MTYPE_HOST, fname);
718e3744 3780
3781 return CMD_SUCCESS;
3782}
3783
274a4a44 3784DEFUN (config_log_file,
3785 config_log_file_cmd,
3786 "log file FILENAME",
3787 "Logging control\n"
3788 "Logging to file\n"
3789 "Logging filename\n")
3790{
3791 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3792}
3793
3794DEFUN (config_log_file_level,
3795 config_log_file_level_cmd,
3796 "log file FILENAME "LOG_LEVELS,
3797 "Logging control\n"
3798 "Logging to file\n"
3799 "Logging filename\n"
3800 LOG_LEVEL_DESC)
3801{
3802 int level;
3803
3804 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3805 return CMD_ERR_NO_MATCH;
3806 return set_log_file(vty, argv[0], level);
3807}
3808
718e3744 3809DEFUN (no_config_log_file,
3810 no_config_log_file_cmd,
3811 "no log file [FILENAME]",
3812 NO_STR
3813 "Logging control\n"
3814 "Cancel logging to file\n"
3815 "Logging file name\n")
3816{
3817 zlog_reset_file (NULL);
3818
3819 if (host.logfile)
05865c90 3820 XFREE (MTYPE_HOST, host.logfile);
718e3744 3821
3822 host.logfile = NULL;
3823
3824 return CMD_SUCCESS;
3825}
3826
274a4a44 3827ALIAS (no_config_log_file,
3828 no_config_log_file_level_cmd,
3829 "no log file FILENAME LEVEL",
3830 NO_STR
3831 "Logging control\n"
3832 "Cancel logging to file\n"
3833 "Logging file name\n"
3834 "Logging level\n")
3835
718e3744 3836DEFUN (config_log_syslog,
3837 config_log_syslog_cmd,
3838 "log syslog",
3839 "Logging control\n"
274a4a44 3840 "Set syslog logging level\n")
718e3744 3841{
274a4a44 3842 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
12ab19f1 3843 return CMD_SUCCESS;
3844}
3845
274a4a44 3846DEFUN (config_log_syslog_level,
3847 config_log_syslog_level_cmd,
3848 "log syslog "LOG_LEVELS,
12ab19f1 3849 "Logging control\n"
274a4a44 3850 "Set syslog logging level\n"
3851 LOG_LEVEL_DESC)
3852{
3853 int level;
12ab19f1 3854
274a4a44 3855 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3856 return CMD_ERR_NO_MATCH;
3857 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3858 return CMD_SUCCESS;
3859}
3860
3861DEFUN_DEPRECATED (config_log_syslog_facility,
3862 config_log_syslog_facility_cmd,
3863 "log syslog facility "LOG_FACILITIES,
3864 "Logging control\n"
3865 "Logging goes to syslog\n"
3866 "(Deprecated) Facility parameter for syslog messages\n"
3867 LOG_FACILITY_DESC)
3868{
3869 int facility;
3870
3871 if ((facility = facility_match(argv[0])) < 0)
3872 return CMD_ERR_NO_MATCH;
12ab19f1 3873
274a4a44 3874 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3875 zlog_default->facility = facility;
718e3744 3876 return CMD_SUCCESS;
3877}
3878
3879DEFUN (no_config_log_syslog,
3880 no_config_log_syslog_cmd,
274a4a44 3881 "no log syslog [LEVEL]",
718e3744 3882 NO_STR
3883 "Logging control\n"
274a4a44 3884 "Cancel logging to syslog\n"
3885 "Logging level\n")
718e3744 3886{
274a4a44 3887 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
718e3744 3888 return CMD_SUCCESS;
3889}
3890
12ab19f1 3891ALIAS (no_config_log_syslog,
3892 no_config_log_syslog_facility_cmd,
274a4a44 3893 "no log syslog facility "LOG_FACILITIES,
12ab19f1 3894 NO_STR
3895 "Logging control\n"
3896 "Logging goes to syslog\n"
3897 "Facility parameter for syslog messages\n"
274a4a44 3898 LOG_FACILITY_DESC)
3899
3900DEFUN (config_log_facility,
3901 config_log_facility_cmd,
3902 "log facility "LOG_FACILITIES,
718e3744 3903 "Logging control\n"
274a4a44 3904 "Facility parameter for syslog messages\n"
3905 LOG_FACILITY_DESC)
718e3744 3906{
274a4a44 3907 int facility;
3908
3909 if ((facility = facility_match(argv[0])) < 0)
3910 return CMD_ERR_NO_MATCH;
3911 zlog_default->facility = facility;
3912 return CMD_SUCCESS;
718e3744 3913}
3914
274a4a44 3915DEFUN (no_config_log_facility,
3916 no_config_log_facility_cmd,
3917 "no log facility [FACILITY]",
718e3744 3918 NO_STR
3919 "Logging control\n"
274a4a44 3920 "Reset syslog facility to default (daemon)\n"
3921 "Syslog facility\n")
3922{
3923 zlog_default->facility = LOG_DAEMON;
3924 return CMD_SUCCESS;
3925}
3926
3927DEFUN_DEPRECATED (config_log_trap,
3928 config_log_trap_cmd,
3929 "log trap "LOG_LEVELS,
3930 "Logging control\n"
3931 "(Deprecated) Set logging level and default for all destinations\n"
3932 LOG_LEVEL_DESC)
3933{
3934 int new_level ;
3935 int i;
3936
3937 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3938 return CMD_ERR_NO_MATCH;
3939
3940 zlog_default->default_lvl = new_level;
3941 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3942 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3943 zlog_default->maxlvl[i] = new_level;
3944 return CMD_SUCCESS;
3945}
3946
3947DEFUN_DEPRECATED (no_config_log_trap,
3948 no_config_log_trap_cmd,
3949 "no log trap [LEVEL]",
3950 NO_STR
3951 "Logging control\n"
3952 "Permit all logging information\n"
3953 "Logging level\n")
718e3744 3954{
274a4a44 3955 zlog_default->default_lvl = LOG_DEBUG;
718e3744 3956 return CMD_SUCCESS;
3957}
3958
3959DEFUN (config_log_record_priority,
3960 config_log_record_priority_cmd,
3961 "log record-priority",
3962 "Logging control\n"
3963 "Log the priority of the message within the message\n")
3964{
3965 zlog_default->record_priority = 1 ;
3966 return CMD_SUCCESS;
3967}
3968
3969DEFUN (no_config_log_record_priority,
3970 no_config_log_record_priority_cmd,
3971 "no log record-priority",
3972 NO_STR
3973 "Logging control\n"
3974 "Do not log the priority of the message within the message\n")
3975{
3976 zlog_default->record_priority = 0 ;
3977 return CMD_SUCCESS;
3978}
3979
1ed72e0b
AS
3980DEFUN (config_log_timestamp_precision,
3981 config_log_timestamp_precision_cmd,
3982 "log timestamp precision <0-6>",
3983 "Logging control\n"
3984 "Timestamp configuration\n"
3985 "Set the timestamp precision\n"
3986 "Number of subsecond digits\n")
3987{
3988 if (argc != 1)
3989 {
3990 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3991 return CMD_WARNING;
3992 }
3993
3994 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3995 zlog_default->timestamp_precision, argv[0], 0, 6);
3996 return CMD_SUCCESS;
3997}
3998
3999DEFUN (no_config_log_timestamp_precision,
4000 no_config_log_timestamp_precision_cmd,
4001 "no log timestamp precision",
4002 NO_STR
4003 "Logging control\n"
4004 "Timestamp configuration\n"
4005 "Reset the timestamp precision to the default value of 0\n")
4006{
4007 zlog_default->timestamp_precision = 0 ;
4008 return CMD_SUCCESS;
4009}
4010
7cfc61d3
DS
4011int
4012cmd_banner_motd_file (const char *file)
4013{
4014 if (host.motdfile)
4015 XFREE (MTYPE_HOST, host.motdfile);
4016 host.motdfile = XSTRDUP (MTYPE_HOST, file);
4017
4018 return CMD_SUCCESS;
4019}
4020
3b0c5d9a 4021DEFUN (banner_motd_file,
4022 banner_motd_file_cmd,
4d833e55 4023 "banner motd file FILE",
3b0c5d9a 4024 "Set banner\n"
4025 "Banner for motd\n"
4026 "Banner from a file\n"
4027 "Filename\n")
4028{
7cfc61d3 4029 return cmd_banner_motd_file (argv[0]);
3b0c5d9a 4030}
718e3744 4031
4032DEFUN (banner_motd_default,
4033 banner_motd_default_cmd,
4034 "banner motd default",
4035 "Set banner string\n"
4036 "Strings for motd\n"
4037 "Default string\n")
4038{
4039 host.motd = default_motd;
4040 return CMD_SUCCESS;
4041}
4042
4043DEFUN (no_banner_motd,
4044 no_banner_motd_cmd,
4045 "no banner motd",
4046 NO_STR
4047 "Set banner string\n"
4048 "Strings for motd\n")
4049{
4050 host.motd = NULL;
22085181 4051 if (host.motdfile)
05865c90 4052 XFREE (MTYPE_HOST, host.motdfile);
3b0c5d9a 4053 host.motdfile = NULL;
718e3744 4054 return CMD_SUCCESS;
4055}
4056
4057/* Set config filename. Called from vty.c */
4058void
c0e8c16f 4059host_config_set (const char *filename)
718e3744 4060{
228da428
CC
4061 if (host.config)
4062 XFREE (MTYPE_HOST, host.config);
05865c90 4063 host.config = XSTRDUP (MTYPE_HOST, filename);
718e3744 4064}
4065
4066void
4067install_default (enum node_type node)
4068{
4069 install_element (node, &config_exit_cmd);
4070 install_element (node, &config_quit_cmd);
4071 install_element (node, &config_end_cmd);
4072 install_element (node, &config_help_cmd);
4073 install_element (node, &config_list_cmd);
4074
4075 install_element (node, &config_write_terminal_cmd);
4076 install_element (node, &config_write_file_cmd);
4077 install_element (node, &config_write_memory_cmd);
4078 install_element (node, &config_write_cmd);
4079 install_element (node, &show_running_config_cmd);
4080}
4081
4082/* Initialize command interface. Install basic nodes and commands. */
4083void
4084cmd_init (int terminal)
4085{
cd40b329
CF
4086 command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
4087 token_cr.type = TOKEN_TERMINAL;
4088 token_cr.cmd = command_cr;
4089 token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
228da428 4090
718e3744 4091 /* Allocate initial top vector of commands. */
4092 cmdvec = vector_init (VECTOR_MIN_SIZE);
4093
4094 /* Default host value settings. */
4095 host.name = NULL;
4096 host.password = NULL;
4097 host.enable = NULL;
4098 host.logfile = NULL;
4099 host.config = NULL;
4100 host.lines = -1;
4101 host.motd = default_motd;
3b0c5d9a 4102 host.motdfile = NULL;
718e3744 4103
4104 /* Install top nodes. */
4105 install_node (&view_node, NULL);
4106 install_node (&enable_node, NULL);
4107 install_node (&auth_node, NULL);
4108 install_node (&auth_enable_node, NULL);
62687ff1 4109 install_node (&restricted_node, NULL);
718e3744 4110 install_node (&config_node, config_write_host);
4111
4112 /* Each node's basic commands. */
4113 install_element (VIEW_NODE, &show_version_cmd);
4114 if (terminal)
4115 {
4116 install_element (VIEW_NODE, &config_list_cmd);
4117 install_element (VIEW_NODE, &config_exit_cmd);
4118 install_element (VIEW_NODE, &config_quit_cmd);
4119 install_element (VIEW_NODE, &config_help_cmd);
4120 install_element (VIEW_NODE, &config_enable_cmd);
4121 install_element (VIEW_NODE, &config_terminal_length_cmd);
4122 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
274a4a44 4123 install_element (VIEW_NODE, &show_logging_cmd);
2885f72d 4124 install_element (VIEW_NODE, &echo_cmd);
62687ff1
PJ
4125
4126 install_element (RESTRICTED_NODE, &config_list_cmd);
4127 install_element (RESTRICTED_NODE, &config_exit_cmd);
4128 install_element (RESTRICTED_NODE, &config_quit_cmd);
4129 install_element (RESTRICTED_NODE, &config_help_cmd);
4130 install_element (RESTRICTED_NODE, &config_enable_cmd);
4131 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
4132 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
4133 install_element (RESTRICTED_NODE, &echo_cmd);
718e3744 4134 }
4135
4136 if (terminal)
4137 {
4138 install_default (ENABLE_NODE);
4139 install_element (ENABLE_NODE, &config_disable_cmd);
4140 install_element (ENABLE_NODE, &config_terminal_cmd);
4141 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
4142 }
4143 install_element (ENABLE_NODE, &show_startup_config_cmd);
4144 install_element (ENABLE_NODE, &show_version_cmd);
718e3744 4145
718e3744 4146 if (terminal)
4147 {
e7168df4 4148 install_element (ENABLE_NODE, &config_terminal_length_cmd);
4149 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
274a4a44 4150 install_element (ENABLE_NODE, &show_logging_cmd);
2885f72d 4151 install_element (ENABLE_NODE, &echo_cmd);
274a4a44 4152 install_element (ENABLE_NODE, &config_logmsg_cmd);
e7168df4 4153
4154 install_default (CONFIG_NODE);
ea8e9d97 4155 }
4156
4157 install_element (CONFIG_NODE, &hostname_cmd);
4158 install_element (CONFIG_NODE, &no_hostname_cmd);
e7168df4 4159
ea8e9d97 4160 if (terminal)
4161 {
e7168df4 4162 install_element (CONFIG_NODE, &password_cmd);
4163 install_element (CONFIG_NODE, &password_text_cmd);
4164 install_element (CONFIG_NODE, &enable_password_cmd);
4165 install_element (CONFIG_NODE, &enable_password_text_cmd);
4166 install_element (CONFIG_NODE, &no_enable_password_cmd);
4167
718e3744 4168 install_element (CONFIG_NODE, &config_log_stdout_cmd);
274a4a44 4169 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
718e3744 4170 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
274a4a44 4171 install_element (CONFIG_NODE, &config_log_monitor_cmd);
4172 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
4173 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
718e3744 4174 install_element (CONFIG_NODE, &config_log_file_cmd);
274a4a44 4175 install_element (CONFIG_NODE, &config_log_file_level_cmd);
718e3744 4176 install_element (CONFIG_NODE, &no_config_log_file_cmd);
274a4a44 4177 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
718e3744 4178 install_element (CONFIG_NODE, &config_log_syslog_cmd);
274a4a44 4179 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
12ab19f1 4180 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
718e3744 4181 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
12ab19f1 4182 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
274a4a44 4183 install_element (CONFIG_NODE, &config_log_facility_cmd);
4184 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
718e3744 4185 install_element (CONFIG_NODE, &config_log_trap_cmd);
4186 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
4187 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
4188 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
1ed72e0b
AS
4189 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
4190 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
718e3744 4191 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
4192 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
4193 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3b0c5d9a 4194 install_element (CONFIG_NODE, &banner_motd_file_cmd);
718e3744 4195 install_element (CONFIG_NODE, &no_banner_motd_cmd);
4196 install_element (CONFIG_NODE, &service_terminal_length_cmd);
4197 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
718e3744 4198
354d119a 4199 install_element (VIEW_NODE, &show_thread_cpu_cmd);
4200 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
62687ff1 4201 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
e276eb82
PJ
4202
4203 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
354d119a 4204 install_element (VIEW_NODE, &show_work_queues_cmd);
4205 install_element (ENABLE_NODE, &show_work_queues_cmd);
19dc275e
DS
4206
4207 vrf_install_commands ();
9ab6812d 4208 }
718e3744 4209 srand(time(NULL));
4210}
228da428 4211
cd40b329
CF
4212static void
4213cmd_terminate_token(struct cmd_token *token)
4214{
4215 unsigned int i, j;
4216 vector keyword_vect;
4217
4218 if (token->multiple)
4219 {
4220 for (i = 0; i < vector_active(token->multiple); i++)
4221 cmd_terminate_token(vector_slot(token->multiple, i));
4222 vector_free(token->multiple);
4223 token->multiple = NULL;
4224 }
4225
4226 if (token->keyword)
4227 {
4228 for (i = 0; i < vector_active(token->keyword); i++)
4229 {
4230 keyword_vect = vector_slot(token->keyword, i);
4231 for (j = 0; j < vector_active(keyword_vect); j++)
4232 cmd_terminate_token(vector_slot(keyword_vect, j));
4233 vector_free(keyword_vect);
4234 }
4235 vector_free(token->keyword);
4236 token->keyword = NULL;
4237 }
4238
4239 XFREE(MTYPE_CMD_TOKENS, token->cmd);
4240 XFREE(MTYPE_CMD_TOKENS, token->desc);
4241
4242 XFREE(MTYPE_CMD_TOKENS, token);
4243}
4244
4245static void
4246cmd_terminate_element(struct cmd_element *cmd)
4247{
4248 unsigned int i;
4249
4250 if (cmd->tokens == NULL)
4251 return;
4252
4253 for (i = 0; i < vector_active(cmd->tokens); i++)
4254 cmd_terminate_token(vector_slot(cmd->tokens, i));
4255
4256 vector_free(cmd->tokens);
4257 cmd->tokens = NULL;
4258}
4259
228da428
CC
4260void
4261cmd_terminate ()
4262{
cd40b329 4263 unsigned int i, j;
228da428
CC
4264 struct cmd_node *cmd_node;
4265 struct cmd_element *cmd_element;
cd40b329 4266 vector cmd_node_v;
228da428
CC
4267
4268 if (cmdvec)
4269 {
4270 for (i = 0; i < vector_active (cmdvec); i++)
4271 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
4272 {
4273 cmd_node_v = cmd_node->cmd_vector;
4274
4275 for (j = 0; j < vector_active (cmd_node_v); j++)
cd40b329
CF
4276 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
4277 cmd_terminate_element(cmd_element);
228da428
CC
4278
4279 vector_free (cmd_node_v);
4280 }
4281
4282 vector_free (cmdvec);
4283 cmdvec = NULL;
4284 }
4285
4286 if (command_cr)
cd40b329
CF
4287 XFREE(MTYPE_CMD_TOKENS, command_cr);
4288 if (token_cr.desc)
4289 XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
228da428
CC
4290 if (host.name)
4291 XFREE (MTYPE_HOST, host.name);
4292 if (host.password)
4293 XFREE (MTYPE_HOST, host.password);
4294 if (host.password_encrypt)
4295 XFREE (MTYPE_HOST, host.password_encrypt);
4296 if (host.enable)
4297 XFREE (MTYPE_HOST, host.enable);
4298 if (host.enable_encrypt)
4299 XFREE (MTYPE_HOST, host.enable_encrypt);
4300 if (host.logfile)
4301 XFREE (MTYPE_HOST, host.logfile);
4302 if (host.motdfile)
4303 XFREE (MTYPE_HOST, host.motdfile);
4304 if (host.config)
4305 XFREE (MTYPE_HOST, host.config);
4306}