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