blob: 8870a42115e84cce1be4d5e011eb7c3d5b3f70d6 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
ajs274a4a42004-12-07 15:39:31 +00002 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00003 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
Christian Frankecd40b322013-09-30 12:27:51 +00004 Copyright (C) 2013 by Open Source Routing.
5 Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC")
paul718e3742002-12-13 20:15:29 +00006
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
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul354d1192005-04-25 16:26:42 +000034#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000035
36/* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000038vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000039
Christian Frankecd40b322013-09-30 12:27:51 +000040struct cmd_token token_cr;
Chris Caputo228da422009-07-18 05:44:03 +000041char *command_cr = NULL;
42
Christian Frankecd40b322013-09-30 12:27:51 +000043enum filter_type
44{
45 FILTER_RELAXED,
46 FILTER_STRICT
47};
48
49enum matcher_rv
50{
51 MATCHER_OK,
52 MATCHER_COMPLETE,
53 MATCHER_INCOMPLETE,
54 MATCHER_NO_MATCH,
55 MATCHER_AMBIGUOUS,
56 MATCHER_EXCEED_ARGC_MAX
57};
58
59#define MATCHER_ERROR(matcher_rv) \
60 ( (matcher_rv) == MATCHER_INCOMPLETE \
61 || (matcher_rv) == MATCHER_NO_MATCH \
62 || (matcher_rv) == MATCHER_AMBIGUOUS \
63 || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \
64 )
65
paul718e3742002-12-13 20:15:29 +000066/* Host information structure. */
67struct host host;
68
paul718e3742002-12-13 20:15:29 +000069/* Standard command node structures. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080070static struct cmd_node auth_node =
paul718e3742002-12-13 20:15:29 +000071{
72 AUTH_NODE,
73 "Password: ",
74};
75
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080076static struct cmd_node view_node =
paul718e3742002-12-13 20:15:29 +000077{
78 VIEW_NODE,
79 "%s> ",
80};
81
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080082static struct cmd_node restricted_node =
Paul Jakma62687ff2008-08-23 14:27:06 +010083{
84 RESTRICTED_NODE,
85 "%s$ ",
86};
87
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080088static struct cmd_node auth_enable_node =
paul718e3742002-12-13 20:15:29 +000089{
90 AUTH_ENABLE_NODE,
91 "Password: ",
92};
93
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080094static struct cmd_node enable_node =
paul718e3742002-12-13 20:15:29 +000095{
96 ENABLE_NODE,
97 "%s# ",
98};
99
Stephen Hemminger7fc626d2008-12-01 11:10:34 -0800100static struct cmd_node config_node =
paul718e3742002-12-13 20:15:29 +0000101{
102 CONFIG_NODE,
103 "%s(config)# ",
104 1
105};
hasso6590f2c2004-10-19 20:40:08 +0000106
107/* Default motd string. */
Everton Marques74b4fad2014-09-18 12:06:53 -0300108static const char *default_motd =
hasso6590f2c2004-10-19 20:40:08 +0000109"\r\n\
110Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
111" QUAGGA_COPYRIGHT "\r\n\
David Lamparter0be793e2012-11-27 01:34:56 +0000112" GIT_INFO "\r\n";
hasso6590f2c2004-10-19 20:40:08 +0000113
ajs274a4a42004-12-07 15:39:31 +0000114
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300115static const struct facility_map {
ajs274a4a42004-12-07 15:39:31 +0000116 int facility;
117 const char *name;
118 size_t match;
119} syslog_facilities[] =
120 {
121 { LOG_KERN, "kern", 1 },
122 { LOG_USER, "user", 2 },
123 { LOG_MAIL, "mail", 1 },
124 { LOG_DAEMON, "daemon", 1 },
125 { LOG_AUTH, "auth", 1 },
126 { LOG_SYSLOG, "syslog", 1 },
127 { LOG_LPR, "lpr", 2 },
128 { LOG_NEWS, "news", 1 },
129 { LOG_UUCP, "uucp", 2 },
130 { LOG_CRON, "cron", 1 },
131#ifdef LOG_FTP
132 { LOG_FTP, "ftp", 1 },
133#endif
134 { LOG_LOCAL0, "local0", 6 },
135 { LOG_LOCAL1, "local1", 6 },
136 { LOG_LOCAL2, "local2", 6 },
137 { LOG_LOCAL3, "local3", 6 },
138 { LOG_LOCAL4, "local4", 6 },
139 { LOG_LOCAL5, "local5", 6 },
140 { LOG_LOCAL6, "local6", 6 },
141 { LOG_LOCAL7, "local7", 6 },
142 { 0, NULL, 0 },
143 };
144
145static const char *
146facility_name(int facility)
147{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300148 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000149
150 for (fm = syslog_facilities; fm->name; fm++)
151 if (fm->facility == facility)
152 return fm->name;
153 return "";
154}
155
156static int
157facility_match(const char *str)
158{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300159 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000160
161 for (fm = syslog_facilities; fm->name; fm++)
162 if (!strncmp(str,fm->name,fm->match))
163 return fm->facility;
164 return -1;
165}
166
167static int
168level_match(const char *s)
169{
170 int level ;
171
172 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
173 if (!strncmp (s, zlog_priority[level], 2))
174 return level;
175 return ZLOG_DISABLED;
176}
177
ajscb585b62005-01-14 17:09:38 +0000178/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000179void
180print_version (const char *progname)
181{
ajscb585b62005-01-14 17:09:38 +0000182 printf ("%s version %s\n", progname, QUAGGA_VERSION);
183 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000184}
185
David Lamparter6b0655a2014-06-04 06:53:35 +0200186
paul718e3742002-12-13 20:15:29 +0000187/* Utility function to concatenate argv argument into a single string
188 with inserting ' ' character between each argument. */
189char *
paul42d49862004-10-13 05:22:18 +0000190argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000191{
192 int i;
ajsf6834d42005-01-28 20:28:35 +0000193 size_t len;
paul718e3742002-12-13 20:15:29 +0000194 char *str;
ajsf6834d42005-01-28 20:28:35 +0000195 char *p;
paul718e3742002-12-13 20:15:29 +0000196
ajsf6834d42005-01-28 20:28:35 +0000197 len = 0;
198 for (i = shift; i < argc; i++)
199 len += strlen(argv[i])+1;
200 if (!len)
201 return NULL;
202 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000203 for (i = shift; i < argc; i++)
204 {
ajsf6834d42005-01-28 20:28:35 +0000205 size_t arglen;
206 memcpy(p, argv[i], (arglen = strlen(argv[i])));
207 p += arglen;
208 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000209 }
ajsf6834d42005-01-28 20:28:35 +0000210 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000211 return str;
212}
213
214/* Install top node of command vector. */
215void
216install_node (struct cmd_node *node,
217 int (*func) (struct vty *))
218{
219 vector_set_index (cmdvec, node->node, node);
220 node->func = func;
221 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
222}
223
paul718e3742002-12-13 20:15:29 +0000224/* Breaking up string into each command piece. I assume given
225 character is separated by a space character. Return value is a
226 vector which includes char ** data element. */
227vector
hassoea8e9d92004-10-07 21:32:14 +0000228cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000229{
hassoea8e9d92004-10-07 21:32:14 +0000230 const char *cp, *start;
231 char *token;
paul718e3742002-12-13 20:15:29 +0000232 int strlen;
233 vector strvec;
234
235 if (string == NULL)
236 return NULL;
237
238 cp = string;
239
240 /* Skip white spaces. */
241 while (isspace ((int) *cp) && *cp != '\0')
242 cp++;
243
244 /* Return if there is only white spaces */
245 if (*cp == '\0')
246 return NULL;
247
248 if (*cp == '!' || *cp == '#')
249 return NULL;
250
251 /* Prepare return vector. */
252 strvec = vector_init (VECTOR_MIN_SIZE);
253
254 /* Copy each command piece and set into vector. */
255 while (1)
256 {
257 start = cp;
258 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
259 *cp != '\0')
260 cp++;
261 strlen = cp - start;
262 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
263 memcpy (token, start, strlen);
264 *(token + strlen) = '\0';
265 vector_set (strvec, token);
266
267 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
268 *cp != '\0')
269 cp++;
270
271 if (*cp == '\0')
272 return strvec;
273 }
274}
275
276/* Free allocated string vector. */
277void
278cmd_free_strvec (vector v)
279{
hasso8c328f12004-10-05 21:01:23 +0000280 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000281 char *cp;
282
283 if (!v)
284 return;
285
paul55468c82005-03-14 20:19:01 +0000286 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000287 if ((cp = vector_slot (v, i)) != NULL)
288 XFREE (MTYPE_STRVEC, cp);
289
290 vector_free (v);
291}
292
Christian Frankecd40b322013-09-30 12:27:51 +0000293struct format_parser_state
294{
295 vector topvect; /* Top level vector */
296 vector intvect; /* Intermediate level vector, used when there's
297 * a multiple in a keyword. */
298 vector curvect; /* current vector where read tokens should be
299 appended. */
300
301 const char *string; /* pointer to command string, not modified */
302 const char *cp; /* pointer in command string, moved along while
303 parsing */
304 const char *dp; /* pointer in description string, moved along while
305 parsing */
306
307 int in_keyword; /* flag to remember if we are in a keyword group */
308 int in_multiple; /* flag to remember if we are in a multiple group */
309 int just_read_word; /* flag to remember if the last thing we red was a
310 * real word and not some abstract token */
311};
312
313static void
314format_parser_error(struct format_parser_state *state, const char *message)
315{
316 int offset = state->cp - state->string + 1;
317
318 fprintf(stderr, "\nError parsing command: \"%s\"\n", state->string);
319 fprintf(stderr, " %*c\n", offset, '^');
320 fprintf(stderr, "%s at offset %d.\n", message, offset);
321 fprintf(stderr, "This is a programming error. Check your DEFUNs etc.\n");
322 exit(1);
323}
324
ajs274a4a42004-12-07 15:39:31 +0000325static char *
Christian Frankecd40b322013-09-30 12:27:51 +0000326format_parser_desc_str(struct format_parser_state *state)
paul718e3742002-12-13 20:15:29 +0000327{
hasso6ad96ea2004-10-07 19:33:46 +0000328 const char *cp, *start;
329 char *token;
paul718e3742002-12-13 20:15:29 +0000330 int strlen;
Christian Frankecd40b322013-09-30 12:27:51 +0000331
332 cp = state->dp;
paul718e3742002-12-13 20:15:29 +0000333
334 if (cp == NULL)
335 return NULL;
336
337 /* Skip white spaces. */
338 while (isspace ((int) *cp) && *cp != '\0')
339 cp++;
340
341 /* Return if there is only white spaces */
342 if (*cp == '\0')
343 return NULL;
344
345 start = cp;
346
347 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
348 cp++;
349
350 strlen = cp - start;
Christian Frankecd40b322013-09-30 12:27:51 +0000351 token = XMALLOC (MTYPE_CMD_TOKENS, strlen + 1);
paul718e3742002-12-13 20:15:29 +0000352 memcpy (token, start, strlen);
353 *(token + strlen) = '\0';
354
Christian Frankecd40b322013-09-30 12:27:51 +0000355 state->dp = cp;
paul718e3742002-12-13 20:15:29 +0000356
357 return token;
358}
359
Christian Frankecd40b322013-09-30 12:27:51 +0000360static void
361format_parser_begin_keyword(struct format_parser_state *state)
paul718e3742002-12-13 20:15:29 +0000362{
Christian Frankecd40b322013-09-30 12:27:51 +0000363 struct cmd_token *token;
364 vector keyword_vect;
paul718e3742002-12-13 20:15:29 +0000365
Christian Frankecd40b322013-09-30 12:27:51 +0000366 if (state->in_keyword
367 || state->in_multiple)
368 format_parser_error(state, "Unexpected '{'");
paul718e3742002-12-13 20:15:29 +0000369
Christian Frankecd40b322013-09-30 12:27:51 +0000370 state->cp++;
371 state->in_keyword = 1;
paul718e3742002-12-13 20:15:29 +0000372
Christian Frankecd40b322013-09-30 12:27:51 +0000373 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
374 token->type = TOKEN_KEYWORD;
375 token->keyword = vector_init(VECTOR_MIN_SIZE);
paul718e3742002-12-13 20:15:29 +0000376
Christian Frankecd40b322013-09-30 12:27:51 +0000377 keyword_vect = vector_init(VECTOR_MIN_SIZE);
378 vector_set(token->keyword, keyword_vect);
379
380 vector_set(state->curvect, token);
381 state->curvect = keyword_vect;
382}
383
384static void
385format_parser_begin_multiple(struct format_parser_state *state)
386{
387 struct cmd_token *token;
388
389 if (state->in_keyword == 1)
390 format_parser_error(state, "Keyword starting with '('");
391
392 if (state->in_multiple)
393 format_parser_error(state, "Nested group");
394
395 state->cp++;
396 state->in_multiple = 1;
397 state->just_read_word = 0;
398
399 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
400 token->type = TOKEN_MULTIPLE;
401 token->multiple = vector_init(VECTOR_MIN_SIZE);
402
403 vector_set(state->curvect, token);
404 if (state->curvect != state->topvect)
405 state->intvect = state->curvect;
406 state->curvect = token->multiple;
407}
408
409static void
410format_parser_end_keyword(struct format_parser_state *state)
411{
412 if (state->in_multiple
413 || !state->in_keyword)
414 format_parser_error(state, "Unexpected '}'");
415
416 if (state->in_keyword == 1)
417 format_parser_error(state, "Empty keyword group");
418
419 state->cp++;
420 state->in_keyword = 0;
421 state->curvect = state->topvect;
422}
423
424static void
425format_parser_end_multiple(struct format_parser_state *state)
426{
427 char *dummy;
428
429 if (!state->in_multiple)
430 format_parser_error(state, "Unepexted ')'");
431
432 if (vector_active(state->curvect) == 0)
433 format_parser_error(state, "Empty multiple section");
434
435 if (!state->just_read_word)
paul718e3742002-12-13 20:15:29 +0000436 {
Christian Frankecd40b322013-09-30 12:27:51 +0000437 /* There are constructions like
438 * 'show ip ospf database ... (self-originate|)'
439 * in use.
440 * The old parser reads a description string for the
441 * word '' between |) which will never match.
442 * Simulate this behvaior by dropping the next desc
443 * string in such a case. */
paul718e3742002-12-13 20:15:29 +0000444
Christian Frankecd40b322013-09-30 12:27:51 +0000445 dummy = format_parser_desc_str(state);
446 XFREE(MTYPE_CMD_TOKENS, dummy);
447 }
paul718e3742002-12-13 20:15:29 +0000448
Christian Frankecd40b322013-09-30 12:27:51 +0000449 state->cp++;
450 state->in_multiple = 0;
paul718e3742002-12-13 20:15:29 +0000451
Christian Frankecd40b322013-09-30 12:27:51 +0000452 if (state->intvect)
453 state->curvect = state->intvect;
454 else
455 state->curvect = state->topvect;
456}
paul718e3742002-12-13 20:15:29 +0000457
Christian Frankecd40b322013-09-30 12:27:51 +0000458static void
459format_parser_handle_pipe(struct format_parser_state *state)
460{
461 struct cmd_token *keyword_token;
462 vector keyword_vect;
paul718e3742002-12-13 20:15:29 +0000463
Christian Frankecd40b322013-09-30 12:27:51 +0000464 if (state->in_multiple)
465 {
466 state->just_read_word = 0;
467 state->cp++;
468 }
469 else if (state->in_keyword)
470 {
471 state->in_keyword = 1;
472 state->cp++;
paul718e3742002-12-13 20:15:29 +0000473
Christian Frankecd40b322013-09-30 12:27:51 +0000474 keyword_token = vector_slot(state->topvect,
475 vector_active(state->topvect) - 1);
476 keyword_vect = vector_init(VECTOR_MIN_SIZE);
477 vector_set(keyword_token->keyword, keyword_vect);
478 state->curvect = keyword_vect;
479 }
480 else
481 {
482 format_parser_error(state, "Unexpected '|'");
paul718e3742002-12-13 20:15:29 +0000483 }
484}
485
Christian Frankecd40b322013-09-30 12:27:51 +0000486static void
487format_parser_read_word(struct format_parser_state *state)
paul718e3742002-12-13 20:15:29 +0000488{
Christian Frankecd40b322013-09-30 12:27:51 +0000489 const char *start;
490 int len;
491 char *cmd;
492 struct cmd_token *token;
paul718e3742002-12-13 20:15:29 +0000493
Christian Frankecd40b322013-09-30 12:27:51 +0000494 start = state->cp;
495
496 while (state->cp[0] != '\0'
497 && !strchr("\r\n(){}|", state->cp[0])
498 && !isspace((int)state->cp[0]))
499 state->cp++;
500
501 len = state->cp - start;
502 cmd = XMALLOC(MTYPE_CMD_TOKENS, len + 1);
503 memcpy(cmd, start, len);
504 cmd[len] = '\0';
505
506 token = XCALLOC(MTYPE_CMD_TOKENS, sizeof(*token));
507 token->type = TOKEN_TERMINAL;
508 token->cmd = cmd;
509 token->desc = format_parser_desc_str(state);
510 vector_set(state->curvect, token);
511
512 if (state->in_keyword == 1)
513 state->in_keyword = 2;
514
515 state->just_read_word = 1;
516}
517
518/**
519 * Parse a given command format string and build a tree of tokens from
520 * it that is suitable to be used by the command subsystem.
521 *
522 * @param string Command format string.
523 * @param descstr Description string.
524 * @return A vector of struct cmd_token representing the given command,
525 * or NULL on error.
526 */
527static vector
528cmd_parse_format(const char *string, const char *descstr)
529{
530 struct format_parser_state state;
531
532 if (string == NULL)
533 return NULL;
534
535 memset(&state, 0, sizeof(state));
536 state.topvect = state.curvect = vector_init(VECTOR_MIN_SIZE);
537 state.cp = state.string = string;
538 state.dp = descstr;
539
540 while (1)
paul718e3742002-12-13 20:15:29 +0000541 {
Christian Frankecd40b322013-09-30 12:27:51 +0000542 while (isspace((int)state.cp[0]) && state.cp[0] != '\0')
543 state.cp++;
544
545 switch (state.cp[0])
546 {
547 case '\0':
548 if (state.in_keyword
549 || state.in_multiple)
550 format_parser_error(&state, "Unclosed group/keyword");
551 return state.topvect;
552 case '{':
553 format_parser_begin_keyword(&state);
554 break;
555 case '(':
556 format_parser_begin_multiple(&state);
557 break;
558 case '}':
559 format_parser_end_keyword(&state);
560 break;
561 case ')':
562 format_parser_end_multiple(&state);
563 break;
564 case '|':
565 format_parser_handle_pipe(&state);
566 break;
567 default:
568 format_parser_read_word(&state);
569 }
paul718e3742002-12-13 20:15:29 +0000570 }
paul718e3742002-12-13 20:15:29 +0000571}
572
573/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000574const char *
paul718e3742002-12-13 20:15:29 +0000575cmd_prompt (enum node_type node)
576{
577 struct cmd_node *cnode;
578
579 cnode = vector_slot (cmdvec, node);
580 return cnode->prompt;
581}
582
583/* Install a command into a node. */
584void
585install_element (enum node_type ntype, struct cmd_element *cmd)
586{
587 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000588
589 /* cmd_init hasn't been called */
590 if (!cmdvec)
591 return;
592
paul718e3742002-12-13 20:15:29 +0000593 cnode = vector_slot (cmdvec, ntype);
594
595 if (cnode == NULL)
596 {
597 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
598 ntype);
599 exit (1);
600 }
601
602 vector_set (cnode->cmd_vector, cmd);
Christian Frankecd40b322013-09-30 12:27:51 +0000603 if (cmd->tokens == NULL)
604 cmd->tokens = cmd_parse_format(cmd->string, cmd->doc);
paul718e3742002-12-13 20:15:29 +0000605}
606
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300607static const unsigned char itoa64[] =
paul718e3742002-12-13 20:15:29 +0000608"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
609
ajs274a4a42004-12-07 15:39:31 +0000610static void
paul718e3742002-12-13 20:15:29 +0000611to64(char *s, long v, int n)
612{
613 while (--n >= 0)
614 {
615 *s++ = itoa64[v&0x3f];
616 v >>= 6;
617 }
618}
619
ajs274a4a42004-12-07 15:39:31 +0000620static char *
621zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000622{
623 char salt[6];
624 struct timeval tv;
625 char *crypt (const char *, const char *);
626
627 gettimeofday(&tv,0);
628
629 to64(&salt[0], random(), 3);
630 to64(&salt[3], tv.tv_usec, 3);
631 salt[5] = '\0';
632
633 return crypt (passwd, salt);
634}
635
636/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000637static int
paul718e3742002-12-13 20:15:29 +0000638config_write_host (struct vty *vty)
639{
640 if (host.name)
641 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
642
643 if (host.encrypt)
644 {
645 if (host.password_encrypt)
646 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
647 if (host.enable_encrypt)
648 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
649 }
650 else
651 {
652 if (host.password)
653 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
654 if (host.enable)
655 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
656 }
657
ajs274a4a42004-12-07 15:39:31 +0000658 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000659 {
660 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
661 VTY_NEWLINE);
662 vty_out (vty, "log trap %s%s",
663 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
664 }
paul718e3742002-12-13 20:15:29 +0000665
ajs274a4a42004-12-07 15:39:31 +0000666 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000667 {
ajs274a4a42004-12-07 15:39:31 +0000668 vty_out (vty, "log file %s", host.logfile);
669 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
670 vty_out (vty, " %s",
671 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000672 vty_out (vty, "%s", VTY_NEWLINE);
673 }
ajs274a4a42004-12-07 15:39:31 +0000674
675 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
676 {
677 vty_out (vty, "log stdout");
678 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
679 vty_out (vty, " %s",
680 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
681 vty_out (vty, "%s", VTY_NEWLINE);
682 }
683
684 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
685 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
686 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
687 vty_out(vty,"log monitor %s%s",
688 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
689
690 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
691 {
692 vty_out (vty, "log syslog");
693 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
694 vty_out (vty, " %s",
695 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
696 vty_out (vty, "%s", VTY_NEWLINE);
697 }
698
699 if (zlog_default->facility != LOG_DAEMON)
700 vty_out (vty, "log facility %s%s",
701 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000702
703 if (zlog_default->record_priority == 1)
704 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
705
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000706 if (zlog_default->timestamp_precision > 0)
707 vty_out (vty, "log timestamp precision %d%s",
708 zlog_default->timestamp_precision, VTY_NEWLINE);
709
paul718e3742002-12-13 20:15:29 +0000710 if (host.advanced)
711 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
712
713 if (host.encrypt)
714 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
715
716 if (host.lines >= 0)
717 vty_out (vty, "service terminal-length %d%s", host.lines,
718 VTY_NEWLINE);
719
paul3b0c5d92005-03-08 10:43:43 +0000720 if (host.motdfile)
721 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
722 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000723 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
724
725 return 1;
726}
727
728/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000729static vector
paul718e3742002-12-13 20:15:29 +0000730cmd_node_vector (vector v, enum node_type ntype)
731{
732 struct cmd_node *cnode = vector_slot (v, ntype);
733 return cnode->cmd_vector;
734}
735
ajs274a4a42004-12-07 15:39:31 +0000736#if 0
737/* Filter command vector by symbol. This function is not actually used;
738 * should it be deleted? */
739static int
paul718e3742002-12-13 20:15:29 +0000740cmd_filter_by_symbol (char *command, char *symbol)
741{
742 int i, lim;
743
744 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
745 {
746 i = 0;
747 lim = strlen (command);
748 while (i < lim)
749 {
750 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
751 return 1;
752 i++;
753 }
754 return 0;
755 }
756 if (strcmp (symbol, "STRING") == 0)
757 {
758 i = 0;
759 lim = strlen (command);
760 while (i < lim)
761 {
762 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
763 return 1;
764 i++;
765 }
766 return 0;
767 }
768 if (strcmp (symbol, "IFNAME") == 0)
769 {
770 i = 0;
771 lim = strlen (command);
772 while (i < lim)
773 {
774 if (! isalnum ((int) command[i]))
775 return 1;
776 i++;
777 }
778 return 0;
779 }
780 return 0;
781}
ajs274a4a42004-12-07 15:39:31 +0000782#endif
paul718e3742002-12-13 20:15:29 +0000783
784/* Completion match types. */
785enum match_type
786{
787 no_match,
788 extend_match,
789 ipv4_prefix_match,
790 ipv4_match,
791 ipv6_prefix_match,
792 ipv6_match,
793 range_match,
794 vararg_match,
795 partly_match,
796 exact_match
797};
798
ajs274a4a42004-12-07 15:39:31 +0000799static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000800cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000801{
hasso8c328f12004-10-05 21:01:23 +0000802 const char *sp;
paul718e3742002-12-13 20:15:29 +0000803 int dots = 0, nums = 0;
804 char buf[4];
805
806 if (str == NULL)
807 return partly_match;
808
809 for (;;)
810 {
811 memset (buf, 0, sizeof (buf));
812 sp = str;
813 while (*str != '\0')
814 {
815 if (*str == '.')
816 {
817 if (dots >= 3)
818 return no_match;
819
820 if (*(str + 1) == '.')
821 return no_match;
822
823 if (*(str + 1) == '\0')
824 return partly_match;
825
826 dots++;
827 break;
828 }
829 if (!isdigit ((int) *str))
830 return no_match;
831
832 str++;
833 }
834
835 if (str - sp > 3)
836 return no_match;
837
838 strncpy (buf, sp, str - sp);
839 if (atoi (buf) > 255)
840 return no_match;
841
842 nums++;
843
844 if (*str == '\0')
845 break;
846
847 str++;
848 }
849
850 if (nums < 4)
851 return partly_match;
852
853 return exact_match;
854}
855
ajs274a4a42004-12-07 15:39:31 +0000856static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000857cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000858{
hasso8c328f12004-10-05 21:01:23 +0000859 const char *sp;
paul718e3742002-12-13 20:15:29 +0000860 int dots = 0;
861 char buf[4];
862
863 if (str == NULL)
864 return partly_match;
865
866 for (;;)
867 {
868 memset (buf, 0, sizeof (buf));
869 sp = str;
870 while (*str != '\0' && *str != '/')
871 {
872 if (*str == '.')
873 {
874 if (dots == 3)
875 return no_match;
876
877 if (*(str + 1) == '.' || *(str + 1) == '/')
878 return no_match;
879
880 if (*(str + 1) == '\0')
881 return partly_match;
882
883 dots++;
884 break;
885 }
886
887 if (!isdigit ((int) *str))
888 return no_match;
889
890 str++;
891 }
892
893 if (str - sp > 3)
894 return no_match;
895
896 strncpy (buf, sp, str - sp);
897 if (atoi (buf) > 255)
898 return no_match;
899
900 if (dots == 3)
901 {
902 if (*str == '/')
903 {
904 if (*(str + 1) == '\0')
905 return partly_match;
906
907 str++;
908 break;
909 }
910 else if (*str == '\0')
911 return partly_match;
912 }
913
914 if (*str == '\0')
915 return partly_match;
916
917 str++;
918 }
919
920 sp = str;
921 while (*str != '\0')
922 {
923 if (!isdigit ((int) *str))
924 return no_match;
925
926 str++;
927 }
928
929 if (atoi (sp) > 32)
930 return no_match;
931
932 return exact_match;
933}
934
935#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
936#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
937#define STATE_START 1
938#define STATE_COLON 2
939#define STATE_DOUBLE 3
940#define STATE_ADDR 4
941#define STATE_DOT 5
942#define STATE_SLASH 6
943#define STATE_MASK 7
944
paul22e0a9e2003-07-11 17:55:46 +0000945#ifdef HAVE_IPV6
946
ajs274a4a42004-12-07 15:39:31 +0000947static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000948cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000949{
hasso726f9b22003-05-25 21:04:54 +0000950 struct sockaddr_in6 sin6_dummy;
951 int ret;
paul718e3742002-12-13 20:15:29 +0000952
953 if (str == NULL)
954 return partly_match;
955
956 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
957 return no_match;
958
hasso726f9b22003-05-25 21:04:54 +0000959 /* use inet_pton that has a better support,
960 * for example inet_pton can support the automatic addresses:
961 * ::1.2.3.4
962 */
963 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
964
965 if (ret == 1)
966 return exact_match;
967
Roman Hoog Antink7c9c6ae2012-05-09 06:35:34 +0000968 return no_match;
paul718e3742002-12-13 20:15:29 +0000969}
970
ajs274a4a42004-12-07 15:39:31 +0000971static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000972cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000973{
974 int state = STATE_START;
975 int colons = 0, nums = 0, double_colon = 0;
976 int mask;
hasso8c328f12004-10-05 21:01:23 +0000977 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000978 char *endptr = NULL;
979
980 if (str == NULL)
981 return partly_match;
982
983 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
984 return no_match;
985
986 while (*str != '\0' && state != STATE_MASK)
987 {
988 switch (state)
989 {
990 case STATE_START:
991 if (*str == ':')
992 {
993 if (*(str + 1) != ':' && *(str + 1) != '\0')
994 return no_match;
995 colons--;
996 state = STATE_COLON;
997 }
998 else
999 {
1000 sp = str;
1001 state = STATE_ADDR;
1002 }
1003
1004 continue;
1005 case STATE_COLON:
1006 colons++;
1007 if (*(str + 1) == '/')
1008 return no_match;
1009 else if (*(str + 1) == ':')
1010 state = STATE_DOUBLE;
1011 else
1012 {
1013 sp = str + 1;
1014 state = STATE_ADDR;
1015 }
1016 break;
1017 case STATE_DOUBLE:
1018 if (double_colon)
1019 return no_match;
1020
1021 if (*(str + 1) == ':')
1022 return no_match;
1023 else
1024 {
1025 if (*(str + 1) != '\0' && *(str + 1) != '/')
1026 colons++;
1027 sp = str + 1;
1028
1029 if (*(str + 1) == '/')
1030 state = STATE_SLASH;
1031 else
1032 state = STATE_ADDR;
1033 }
1034
1035 double_colon++;
1036 nums += 1;
1037 break;
1038 case STATE_ADDR:
1039 if (*(str + 1) == ':' || *(str + 1) == '.'
1040 || *(str + 1) == '\0' || *(str + 1) == '/')
1041 {
1042 if (str - sp > 3)
1043 return no_match;
1044
1045 for (; sp <= str; sp++)
1046 if (*sp == '/')
1047 return no_match;
1048
1049 nums++;
1050
1051 if (*(str + 1) == ':')
1052 state = STATE_COLON;
1053 else if (*(str + 1) == '.')
David Lamparteraa5cf242012-07-19 16:11:50 +02001054 {
1055 if (colons || double_colon)
1056 state = STATE_DOT;
1057 else
1058 return no_match;
1059 }
paul718e3742002-12-13 20:15:29 +00001060 else if (*(str + 1) == '/')
1061 state = STATE_SLASH;
1062 }
1063 break;
1064 case STATE_DOT:
1065 state = STATE_ADDR;
1066 break;
1067 case STATE_SLASH:
1068 if (*(str + 1) == '\0')
1069 return partly_match;
1070
1071 state = STATE_MASK;
1072 break;
1073 default:
1074 break;
1075 }
1076
1077 if (nums > 11)
1078 return no_match;
1079
1080 if (colons > 7)
1081 return no_match;
1082
1083 str++;
1084 }
1085
1086 if (state < STATE_MASK)
1087 return partly_match;
1088
1089 mask = strtol (str, &endptr, 10);
1090 if (*endptr != '\0')
1091 return no_match;
1092
1093 if (mask < 0 || mask > 128)
1094 return no_match;
1095
1096/* I don't know why mask < 13 makes command match partly.
1097 Forgive me to make this comments. I Want to set static default route
1098 because of lack of function to originate default in ospf6d; sorry
1099 yasu
1100 if (mask < 13)
1101 return partly_match;
1102*/
1103
1104 return exact_match;
1105}
1106
paul22e0a9e2003-07-11 17:55:46 +00001107#endif /* HAVE_IPV6 */
1108
paul718e3742002-12-13 20:15:29 +00001109#define DECIMAL_STRLEN_MAX 10
1110
ajs274a4a42004-12-07 15:39:31 +00001111static int
hasso8c328f12004-10-05 21:01:23 +00001112cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001113{
1114 char *p;
1115 char buf[DECIMAL_STRLEN_MAX + 1];
1116 char *endptr = NULL;
1117 unsigned long min, max, val;
1118
1119 if (str == NULL)
1120 return 1;
1121
1122 val = strtoul (str, &endptr, 10);
1123 if (*endptr != '\0')
1124 return 0;
1125
1126 range++;
1127 p = strchr (range, '-');
1128 if (p == NULL)
1129 return 0;
1130 if (p - range > DECIMAL_STRLEN_MAX)
1131 return 0;
1132 strncpy (buf, range, p - range);
1133 buf[p - range] = '\0';
1134 min = strtoul (buf, &endptr, 10);
1135 if (*endptr != '\0')
1136 return 0;
1137
1138 range = p + 1;
1139 p = strchr (range, '>');
1140 if (p == NULL)
1141 return 0;
1142 if (p - range > DECIMAL_STRLEN_MAX)
1143 return 0;
1144 strncpy (buf, range, p - range);
1145 buf[p - range] = '\0';
1146 max = strtoul (buf, &endptr, 10);
1147 if (*endptr != '\0')
1148 return 0;
1149
1150 if (val < min || val > max)
1151 return 0;
1152
1153 return 1;
1154}
1155
ajs274a4a42004-12-07 15:39:31 +00001156static enum match_type
Christian Frankecd40b322013-09-30 12:27:51 +00001157cmd_word_match(struct cmd_token *token,
1158 enum filter_type filter,
1159 const char *word)
paul718e3742002-12-13 20:15:29 +00001160{
hasso8c328f12004-10-05 21:01:23 +00001161 const char *str;
paul718e3742002-12-13 20:15:29 +00001162 enum match_type match_type;
paul909a2152005-03-14 17:41:45 +00001163
Christian Frankecd40b322013-09-30 12:27:51 +00001164 str = token->cmd;
paul718e3742002-12-13 20:15:29 +00001165
Christian Frankecd40b322013-09-30 12:27:51 +00001166 if (filter == FILTER_RELAXED)
1167 if (!word || !strlen(word))
1168 return partly_match;
paul718e3742002-12-13 20:15:29 +00001169
Christian Frankecd40b322013-09-30 12:27:51 +00001170 if (!word)
1171 return no_match;
paul909a2152005-03-14 17:41:45 +00001172
Christian Frankecd40b322013-09-30 12:27:51 +00001173 if (CMD_VARARG(str))
1174 {
1175 return vararg_match;
1176 }
1177 else if (CMD_RANGE(str))
1178 {
1179 if (cmd_range_match(str, word))
1180 return range_match;
1181 }
paul22e0a9e2003-07-11 17:55:46 +00001182#ifdef HAVE_IPV6
Christian Frankecd40b322013-09-30 12:27:51 +00001183 else if (CMD_IPV6(str))
1184 {
1185 match_type = cmd_ipv6_match(word);
1186 if ((filter == FILTER_RELAXED && match_type != no_match)
1187 || (filter == FILTER_STRICT && match_type == exact_match))
1188 return ipv6_match;
1189 }
1190 else if (CMD_IPV6_PREFIX(str))
1191 {
1192 match_type = cmd_ipv6_prefix_match(word);
1193 if ((filter == FILTER_RELAXED && match_type != no_match)
1194 || (filter == FILTER_STRICT && match_type == exact_match))
1195 return ipv6_prefix_match;
1196 }
1197#endif /* HAVE_IPV6 */
1198 else if (CMD_IPV4(str))
1199 {
1200 match_type = cmd_ipv4_match(word);
1201 if ((filter == FILTER_RELAXED && match_type != no_match)
1202 || (filter == FILTER_STRICT && match_type == exact_match))
1203 return ipv4_match;
1204 }
1205 else if (CMD_IPV4_PREFIX(str))
1206 {
1207 match_type = cmd_ipv4_prefix_match(word);
1208 if ((filter == FILTER_RELAXED && match_type != no_match)
1209 || (filter == FILTER_STRICT && match_type == exact_match))
1210 return ipv4_prefix_match;
1211 }
1212 else if (CMD_OPTION(str) || CMD_VARIABLE(str))
1213 {
1214 return extend_match;
1215 }
1216 else
1217 {
1218 if (filter == FILTER_RELAXED && !strncmp(str, word, strlen(word)))
1219 {
1220 if (!strcmp(str, word))
1221 return exact_match;
1222 return partly_match;
1223 }
1224 if (filter == FILTER_STRICT && !strcmp(str, word))
1225 return exact_match;
1226 }
paul718e3742002-12-13 20:15:29 +00001227
Christian Frankecd40b322013-09-30 12:27:51 +00001228 return no_match;
paul718e3742002-12-13 20:15:29 +00001229}
1230
Christian Frankecd40b322013-09-30 12:27:51 +00001231struct cmd_matcher
1232{
1233 struct cmd_element *cmd; /* The command element the matcher is using */
1234 enum filter_type filter; /* Whether to use strict or relaxed matching */
1235 vector vline; /* The tokenized commandline which is to be matched */
1236 unsigned int index; /* The index up to which matching should be done */
1237
1238 /* If set, construct a list of matches at the position given by index */
1239 enum match_type *match_type;
1240 vector *match;
1241
1242 unsigned int word_index; /* iterating over vline */
1243};
1244
1245static int
1246push_argument(int *argc, const char **argv, const char *arg)
1247{
1248 if (!arg || !strlen(arg))
1249 arg = NULL;
1250
1251 if (!argc || !argv)
1252 return 0;
1253
1254 if (*argc >= CMD_ARGC_MAX)
1255 return -1;
1256
1257 argv[(*argc)++] = arg;
1258 return 0;
1259}
1260
1261static void
1262cmd_matcher_record_match(struct cmd_matcher *matcher,
1263 enum match_type match_type,
1264 struct cmd_token *token)
1265{
1266 if (matcher->word_index != matcher->index)
1267 return;
1268
1269 if (matcher->match)
1270 {
1271 if (!*matcher->match)
1272 *matcher->match = vector_init(VECTOR_MIN_SIZE);
1273 vector_set(*matcher->match, token);
1274 }
1275
1276 if (matcher->match_type)
1277 {
1278 if (match_type > *matcher->match_type)
1279 *matcher->match_type = match_type;
1280 }
1281}
1282
1283static int
1284cmd_matcher_words_left(struct cmd_matcher *matcher)
1285{
1286 return matcher->word_index < vector_active(matcher->vline);
1287}
1288
1289static const char*
1290cmd_matcher_get_word(struct cmd_matcher *matcher)
1291{
1292 assert(cmd_matcher_words_left(matcher));
1293
1294 return vector_slot(matcher->vline, matcher->word_index);
1295}
1296
1297static enum matcher_rv
1298cmd_matcher_match_terminal(struct cmd_matcher *matcher,
1299 struct cmd_token *token,
1300 int *argc, const char **argv)
1301{
1302 const char *word;
1303 enum match_type word_match;
1304
1305 assert(token->type == TOKEN_TERMINAL);
1306
1307 if (!cmd_matcher_words_left(matcher))
1308 {
1309 if (CMD_OPTION(token->cmd))
1310 return MATCHER_OK; /* missing optional args are NOT pushed as NULL */
1311 else
1312 return MATCHER_INCOMPLETE;
1313 }
1314
1315 word = cmd_matcher_get_word(matcher);
1316 word_match = cmd_word_match(token, matcher->filter, word);
1317 if (word_match == no_match)
1318 return MATCHER_NO_MATCH;
1319
1320 /* We have to record the input word as argument if it matched
1321 * against a variable. */
1322 if (CMD_VARARG(token->cmd)
1323 || CMD_VARIABLE(token->cmd)
1324 || CMD_OPTION(token->cmd))
1325 {
1326 if (push_argument(argc, argv, word))
1327 return MATCHER_EXCEED_ARGC_MAX;
1328 }
1329
1330 cmd_matcher_record_match(matcher, word_match, token);
1331
1332 matcher->word_index++;
1333
1334 /* A vararg token should consume all left over words as arguments */
1335 if (CMD_VARARG(token->cmd))
1336 while (cmd_matcher_words_left(matcher))
1337 {
1338 word = cmd_matcher_get_word(matcher);
1339 if (word && strlen(word))
1340 push_argument(argc, argv, word);
1341 matcher->word_index++;
1342 }
1343
1344 return MATCHER_OK;
1345}
1346
1347static enum matcher_rv
1348cmd_matcher_match_multiple(struct cmd_matcher *matcher,
1349 struct cmd_token *token,
1350 int *argc, const char **argv)
1351{
1352 enum match_type multiple_match;
1353 unsigned int multiple_index;
1354 const char *word;
1355 const char *arg;
1356 struct cmd_token *word_token;
1357 enum match_type word_match;
1358
1359 assert(token->type == TOKEN_MULTIPLE);
1360
1361 multiple_match = no_match;
1362
1363 if (!cmd_matcher_words_left(matcher))
1364 return MATCHER_INCOMPLETE;
1365
1366 word = cmd_matcher_get_word(matcher);
1367 for (multiple_index = 0;
1368 multiple_index < vector_active(token->multiple);
1369 multiple_index++)
1370 {
1371 word_token = vector_slot(token->multiple, multiple_index);
1372
1373 word_match = cmd_word_match(word_token, matcher->filter, word);
1374 if (word_match == no_match)
1375 continue;
1376
1377 cmd_matcher_record_match(matcher, word_match, word_token);
1378
1379 if (word_match > multiple_match)
1380 {
1381 multiple_match = word_match;
1382 arg = word;
1383 }
1384 /* To mimic the behavior of the old command implementation, we
1385 * tolerate any ambiguities here :/ */
1386 }
1387
1388 matcher->word_index++;
1389
1390 if (multiple_match == no_match)
1391 return MATCHER_NO_MATCH;
1392
1393 if (push_argument(argc, argv, arg))
1394 return MATCHER_EXCEED_ARGC_MAX;
1395
1396 return MATCHER_OK;
1397}
1398
1399static enum matcher_rv
1400cmd_matcher_read_keywords(struct cmd_matcher *matcher,
1401 struct cmd_token *token,
1402 vector args_vector)
paul718e3742002-12-13 20:15:29 +00001403{
hasso8c328f12004-10-05 21:01:23 +00001404 unsigned int i;
Christian Frankecd40b322013-09-30 12:27:51 +00001405 unsigned long keyword_mask;
1406 unsigned int keyword_found;
1407 enum match_type keyword_match;
1408 enum match_type word_match;
1409 vector keyword_vector;
1410 struct cmd_token *word_token;
1411 const char *word;
1412 int keyword_argc;
1413 const char **keyword_argv;
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001414 enum matcher_rv rv = MATCHER_NO_MATCH;
Christian Frankecd40b322013-09-30 12:27:51 +00001415
1416 keyword_mask = 0;
1417 while (1)
1418 {
1419 if (!cmd_matcher_words_left(matcher))
1420 return MATCHER_OK;
1421
1422 word = cmd_matcher_get_word(matcher);
1423
1424 keyword_found = -1;
1425 keyword_match = no_match;
1426 for (i = 0; i < vector_active(token->keyword); i++)
1427 {
1428 if (keyword_mask & (1 << i))
1429 continue;
1430
1431 keyword_vector = vector_slot(token->keyword, i);
1432 word_token = vector_slot(keyword_vector, 0);
1433
1434 word_match = cmd_word_match(word_token, matcher->filter, word);
1435 if (word_match == no_match)
1436 continue;
1437
1438 cmd_matcher_record_match(matcher, word_match, word_token);
1439
1440 if (word_match > keyword_match)
1441 {
1442 keyword_match = word_match;
1443 keyword_found = i;
1444 }
1445 else if (word_match == keyword_match)
1446 {
1447 if (matcher->word_index != matcher->index || args_vector)
1448 return MATCHER_AMBIGUOUS;
1449 }
1450 }
1451
1452 if (keyword_found == (unsigned int)-1)
1453 return MATCHER_NO_MATCH;
1454
1455 matcher->word_index++;
1456
1457 if (matcher->word_index > matcher->index)
1458 return MATCHER_OK;
1459
1460 keyword_mask |= (1 << keyword_found);
1461
1462 if (args_vector)
1463 {
1464 keyword_argc = 0;
1465 keyword_argv = XMALLOC(MTYPE_TMP, (CMD_ARGC_MAX + 1) * sizeof(char*));
1466 /* We use -1 as a marker for unused fields as NULL might be a valid value */
1467 for (i = 0; i < CMD_ARGC_MAX + 1; i++)
1468 keyword_argv[i] = (void*)-1;
1469 vector_set_index(args_vector, keyword_found, keyword_argv);
1470 }
1471 else
1472 {
1473 keyword_argv = NULL;
1474 }
1475
1476 keyword_vector = vector_slot(token->keyword, keyword_found);
1477 /* the keyword itself is at 0. We are only interested in the arguments,
1478 * so start counting at 1. */
1479 for (i = 1; i < vector_active(keyword_vector); i++)
1480 {
1481 word_token = vector_slot(keyword_vector, i);
1482
1483 switch (word_token->type)
1484 {
1485 case TOKEN_TERMINAL:
1486 rv = cmd_matcher_match_terminal(matcher, word_token,
1487 &keyword_argc, keyword_argv);
1488 break;
1489 case TOKEN_MULTIPLE:
1490 rv = cmd_matcher_match_multiple(matcher, word_token,
1491 &keyword_argc, keyword_argv);
1492 break;
1493 case TOKEN_KEYWORD:
1494 assert(!"Keywords should never be nested.");
1495 break;
1496 }
1497
1498 if (MATCHER_ERROR(rv))
1499 return rv;
1500
1501 if (matcher->word_index > matcher->index)
1502 return MATCHER_OK;
1503 }
1504 }
1505 /* not reached */
1506}
1507
1508static enum matcher_rv
1509cmd_matcher_build_keyword_args(struct cmd_matcher *matcher,
1510 struct cmd_token *token,
1511 int *argc, const char **argv,
1512 vector keyword_args_vector)
1513{
1514 unsigned int i, j;
1515 const char **keyword_args;
1516 vector keyword_vector;
1517 struct cmd_token *word_token;
1518 const char *arg;
1519 enum matcher_rv rv;
1520
1521 rv = MATCHER_OK;
1522
1523 if (keyword_args_vector == NULL)
1524 return rv;
1525
1526 for (i = 0; i < vector_active(token->keyword); i++)
1527 {
1528 keyword_vector = vector_slot(token->keyword, i);
1529 keyword_args = vector_lookup(keyword_args_vector, i);
1530
1531 if (vector_active(keyword_vector) == 1)
1532 {
1533 /* this is a keyword without arguments */
1534 if (keyword_args)
1535 {
1536 word_token = vector_slot(keyword_vector, 0);
1537 arg = word_token->cmd;
1538 }
1539 else
1540 {
1541 arg = NULL;
1542 }
1543
1544 if (push_argument(argc, argv, arg))
1545 rv = MATCHER_EXCEED_ARGC_MAX;
1546 }
1547 else
1548 {
1549 /* this is a keyword with arguments */
1550 if (keyword_args)
1551 {
1552 /* the keyword was present, so just fill in the arguments */
1553 for (j = 0; keyword_args[j] != (void*)-1; j++)
1554 if (push_argument(argc, argv, keyword_args[j]))
1555 rv = MATCHER_EXCEED_ARGC_MAX;
1556 XFREE(MTYPE_TMP, keyword_args);
1557 }
1558 else
1559 {
1560 /* the keyword was not present, insert NULL for the arguments
1561 * the keyword would have taken. */
1562 for (j = 1; j < vector_active(keyword_vector); j++)
1563 {
1564 word_token = vector_slot(keyword_vector, j);
1565 if ((word_token->type == TOKEN_TERMINAL
1566 && (CMD_VARARG(word_token->cmd)
1567 || CMD_VARIABLE(word_token->cmd)
1568 || CMD_OPTION(word_token->cmd)))
1569 || word_token->type == TOKEN_MULTIPLE)
1570 {
1571 if (push_argument(argc, argv, NULL))
1572 rv = MATCHER_EXCEED_ARGC_MAX;
1573 }
1574 }
1575 }
1576 }
1577 }
1578 vector_free(keyword_args_vector);
1579 return rv;
1580}
1581
1582static enum matcher_rv
1583cmd_matcher_match_keyword(struct cmd_matcher *matcher,
1584 struct cmd_token *token,
1585 int *argc, const char **argv)
1586{
1587 vector keyword_args_vector;
1588 enum matcher_rv reader_rv;
1589 enum matcher_rv builder_rv;
1590
1591 assert(token->type == TOKEN_KEYWORD);
1592
1593 if (argc && argv)
1594 keyword_args_vector = vector_init(VECTOR_MIN_SIZE);
1595 else
1596 keyword_args_vector = NULL;
1597
1598 reader_rv = cmd_matcher_read_keywords(matcher, token, keyword_args_vector);
1599 builder_rv = cmd_matcher_build_keyword_args(matcher, token, argc,
1600 argv, keyword_args_vector);
1601 /* keyword_args_vector is consumed by cmd_matcher_build_keyword_args */
1602
1603 if (!MATCHER_ERROR(reader_rv) && MATCHER_ERROR(builder_rv))
1604 return builder_rv;
1605
1606 return reader_rv;
1607}
1608
1609static void
1610cmd_matcher_init(struct cmd_matcher *matcher,
1611 struct cmd_element *cmd,
1612 enum filter_type filter,
1613 vector vline,
1614 unsigned int index,
1615 enum match_type *match_type,
1616 vector *match)
1617{
1618 memset(matcher, 0, sizeof(*matcher));
1619
1620 matcher->cmd = cmd;
1621 matcher->filter = filter;
1622 matcher->vline = vline;
1623 matcher->index = index;
1624
1625 matcher->match_type = match_type;
1626 if (matcher->match_type)
1627 *matcher->match_type = no_match;
1628 matcher->match = match;
1629
1630 matcher->word_index = 0;
1631}
1632
1633static enum matcher_rv
1634cmd_element_match(struct cmd_element *cmd_element,
1635 enum filter_type filter,
1636 vector vline,
1637 unsigned int index,
1638 enum match_type *match_type,
1639 vector *match,
1640 int *argc,
1641 const char **argv)
1642{
1643 struct cmd_matcher matcher;
1644 unsigned int token_index;
Paul Jakma7aa9dce2014-09-19 14:42:23 +01001645 enum matcher_rv rv = MATCHER_NO_MATCH;
Christian Frankecd40b322013-09-30 12:27:51 +00001646
1647 cmd_matcher_init(&matcher, cmd_element, filter,
1648 vline, index, match_type, match);
1649
1650 if (argc != NULL)
1651 *argc = 0;
1652
1653 for (token_index = 0;
1654 token_index < vector_active(cmd_element->tokens);
1655 token_index++)
1656 {
1657 struct cmd_token *token = vector_slot(cmd_element->tokens, token_index);
1658
1659 switch (token->type)
1660 {
1661 case TOKEN_TERMINAL:
1662 rv = cmd_matcher_match_terminal(&matcher, token, argc, argv);
1663 break;
1664 case TOKEN_MULTIPLE:
1665 rv = cmd_matcher_match_multiple(&matcher, token, argc, argv);
1666 break;
1667 case TOKEN_KEYWORD:
1668 rv = cmd_matcher_match_keyword(&matcher, token, argc, argv);
1669 }
1670
1671 if (MATCHER_ERROR(rv))
1672 return rv;
1673
1674 if (matcher.word_index > index)
1675 return MATCHER_OK;
1676 }
1677
1678 /* return MATCHER_COMPLETE if all words were consumed */
1679 if (matcher.word_index >= vector_active(vline))
1680 return MATCHER_COMPLETE;
1681
1682 /* return MATCHER_COMPLETE also if only an empty word is left. */
1683 if (matcher.word_index == vector_active(vline) - 1
1684 && (!vector_slot(vline, matcher.word_index)
1685 || !strlen((char*)vector_slot(vline, matcher.word_index))))
1686 return MATCHER_COMPLETE;
1687
1688 return MATCHER_NO_MATCH; /* command is too long to match */
1689}
1690
1691/**
1692 * Filter a given vector of commands against a given commandline and
1693 * calculate possible completions.
1694 *
1695 * @param commands A vector of struct cmd_element*. Commands that don't
1696 * match against the given command line will be overwritten
1697 * with NULL in that vector.
1698 * @param filter Either FILTER_RELAXED or FILTER_STRICT. This basically
1699 * determines how incomplete commands are handled, compare with
1700 * cmd_word_match for details.
1701 * @param vline A vector of char* containing the tokenized commandline.
1702 * @param index Only match up to the given token of the commandline.
1703 * @param match_type Record the type of the best match here.
1704 * @param matches Record the matches here. For each cmd_element in the commands
1705 * vector, a match vector will be created in the matches vector.
1706 * That vector will contain all struct command_token* of the
1707 * cmd_element which matched against the given vline at the given
1708 * index.
1709 * @return A code specifying if an error occured. If all went right, it's
1710 * CMD_SUCCESS.
1711 */
1712static int
1713cmd_vector_filter(vector commands,
1714 enum filter_type filter,
1715 vector vline,
1716 unsigned int index,
1717 enum match_type *match_type,
1718 vector *matches)
1719{
1720 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001721 struct cmd_element *cmd_element;
Christian Frankecd40b322013-09-30 12:27:51 +00001722 enum match_type best_match;
1723 enum match_type element_match;
1724 enum matcher_rv matcher_rv;
paul909a2152005-03-14 17:41:45 +00001725
Christian Frankecd40b322013-09-30 12:27:51 +00001726 best_match = no_match;
1727 *matches = vector_init(VECTOR_MIN_SIZE);
paul718e3742002-12-13 20:15:29 +00001728
Christian Frankecd40b322013-09-30 12:27:51 +00001729 for (i = 0; i < vector_active (commands); i++)
1730 if ((cmd_element = vector_slot (commands, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001731 {
Christian Frankecd40b322013-09-30 12:27:51 +00001732 vector_set_index(*matches, i, NULL);
1733 matcher_rv = cmd_element_match(cmd_element, filter,
1734 vline, index,
1735 &element_match,
1736 (vector*)&vector_slot(*matches, i),
1737 NULL, NULL);
1738 if (MATCHER_ERROR(matcher_rv))
1739 {
1740 vector_slot(commands, i) = NULL;
1741 if (matcher_rv == MATCHER_AMBIGUOUS)
1742 return CMD_ERR_AMBIGUOUS;
1743 if (matcher_rv == MATCHER_EXCEED_ARGC_MAX)
1744 return CMD_ERR_EXEED_ARGC_MAX;
1745 }
1746 else if (element_match > best_match)
1747 {
1748 best_match = element_match;
1749 }
paul718e3742002-12-13 20:15:29 +00001750 }
Christian Frankecd40b322013-09-30 12:27:51 +00001751 *match_type = best_match;
1752 return CMD_SUCCESS;
1753}
1754
1755/**
1756 * Check whether a given commandline is complete if used for a specific
1757 * cmd_element.
1758 *
1759 * @param cmd_element A cmd_element against which the commandline should be
1760 * checked.
1761 * @param vline The tokenized commandline.
1762 * @return 1 if the given commandline is complete, 0 otherwise.
1763 */
1764static int
1765cmd_is_complete(struct cmd_element *cmd_element,
1766 vector vline)
1767{
1768 enum matcher_rv rv;
1769
1770 rv = cmd_element_match(cmd_element,
1771 FILTER_RELAXED,
1772 vline, -1,
1773 NULL, NULL,
1774 NULL, NULL);
1775 return (rv == MATCHER_COMPLETE);
1776}
1777
1778/**
1779 * Parse a given commandline and construct a list of arguments for the
1780 * given command_element.
1781 *
1782 * @param cmd_element The cmd_element for which we want to construct arguments.
1783 * @param vline The tokenized commandline.
1784 * @param argc Where to store the argument count.
1785 * @param argv Where to store the argument list. Should be at least
1786 * CMD_ARGC_MAX elements long.
1787 * @return CMD_SUCCESS if everything went alright, an error otherwise.
1788 */
1789static int
1790cmd_parse(struct cmd_element *cmd_element,
1791 vector vline,
1792 int *argc, const char **argv)
1793{
1794 enum matcher_rv rv = cmd_element_match(cmd_element,
1795 FILTER_RELAXED,
1796 vline, -1,
1797 NULL, NULL,
1798 argc, argv);
1799 switch (rv)
1800 {
1801 case MATCHER_COMPLETE:
1802 return CMD_SUCCESS;
1803
1804 case MATCHER_NO_MATCH:
1805 return CMD_ERR_NO_MATCH;
1806
1807 case MATCHER_AMBIGUOUS:
1808 return CMD_ERR_AMBIGUOUS;
1809
1810 case MATCHER_EXCEED_ARGC_MAX:
1811 return CMD_ERR_EXEED_ARGC_MAX;
1812
1813 default:
1814 return CMD_ERR_INCOMPLETE;
1815 }
paul718e3742002-12-13 20:15:29 +00001816}
1817
1818/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001819static int
Christian Frankecd40b322013-09-30 12:27:51 +00001820is_cmd_ambiguous (vector cmd_vector,
1821 const char *command,
1822 vector matches,
1823 enum match_type type)
paul718e3742002-12-13 20:15:29 +00001824{
hasso8c328f12004-10-05 21:01:23 +00001825 unsigned int i;
1826 unsigned int j;
1827 const char *str = NULL;
hasso8c328f12004-10-05 21:01:23 +00001828 const char *matched = NULL;
Christian Frankecd40b322013-09-30 12:27:51 +00001829 vector match_vector;
1830 struct cmd_token *cmd_token;
paul909a2152005-03-14 17:41:45 +00001831
Christian Frankecd40b322013-09-30 12:27:51 +00001832 if (command == NULL)
1833 command = "";
1834
1835 for (i = 0; i < vector_active (matches); i++)
1836 if ((match_vector = vector_slot (matches, i)) != NULL)
paul718e3742002-12-13 20:15:29 +00001837 {
1838 int match = 0;
1839
Christian Frankecd40b322013-09-30 12:27:51 +00001840 for (j = 0; j < vector_active (match_vector); j++)
1841 if ((cmd_token = vector_slot (match_vector, j)) != NULL)
paul909a2152005-03-14 17:41:45 +00001842 {
1843 enum match_type ret;
Christian Frankecd40b322013-09-30 12:27:51 +00001844
1845 assert(cmd_token->type == TOKEN_TERMINAL);
1846 if (cmd_token->type != TOKEN_TERMINAL)
1847 continue;
1848
1849 str = cmd_token->cmd;
paul718e3742002-12-13 20:15:29 +00001850
paul909a2152005-03-14 17:41:45 +00001851 switch (type)
1852 {
1853 case exact_match:
1854 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1855 && strcmp (command, str) == 0)
1856 match++;
1857 break;
1858 case partly_match:
1859 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1860 && strncmp (command, str, strlen (command)) == 0)
1861 {
1862 if (matched && strcmp (matched, str) != 0)
1863 return 1; /* There is ambiguous match. */
1864 else
1865 matched = str;
1866 match++;
1867 }
1868 break;
1869 case range_match:
1870 if (cmd_range_match (str, command))
1871 {
1872 if (matched && strcmp (matched, str) != 0)
1873 return 1;
1874 else
1875 matched = str;
1876 match++;
1877 }
1878 break;
1879#ifdef HAVE_IPV6
1880 case ipv6_match:
1881 if (CMD_IPV6 (str))
1882 match++;
1883 break;
1884 case ipv6_prefix_match:
1885 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1886 {
1887 if (ret == partly_match)
1888 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001889
paul909a2152005-03-14 17:41:45 +00001890 match++;
1891 }
1892 break;
1893#endif /* HAVE_IPV6 */
1894 case ipv4_match:
1895 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001896 match++;
paul909a2152005-03-14 17:41:45 +00001897 break;
1898 case ipv4_prefix_match:
1899 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1900 {
1901 if (ret == partly_match)
1902 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001903
paul909a2152005-03-14 17:41:45 +00001904 match++;
1905 }
1906 break;
1907 case extend_match:
1908 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001909 match++;
paul909a2152005-03-14 17:41:45 +00001910 break;
1911 case no_match:
1912 default:
1913 break;
1914 }
1915 }
1916 if (!match)
Christian Frankecd40b322013-09-30 12:27:51 +00001917 vector_slot (cmd_vector, i) = NULL;
paul718e3742002-12-13 20:15:29 +00001918 }
1919 return 0;
1920}
1921
1922/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001923static const char *
hasso8c328f12004-10-05 21:01:23 +00001924cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001925{
1926 /* Skip variable arguments. */
1927 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1928 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1929 return NULL;
1930
1931 /* In case of 'command \t', given src is NULL string. */
1932 if (src == NULL)
1933 return dst;
1934
1935 /* Matched with input string. */
1936 if (strncmp (src, dst, strlen (src)) == 0)
1937 return dst;
1938
1939 return NULL;
1940}
1941
1942/* If src matches dst return dst string, otherwise return NULL */
1943/* This version will return the dst string always if it is
1944 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001945static const char *
hasso8c328f12004-10-05 21:01:23 +00001946cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001947{
1948 if (CMD_VARARG (dst))
1949 return dst;
1950
1951 if (CMD_RANGE (dst))
1952 {
1953 if (cmd_range_match (dst, src))
1954 return dst;
1955 else
1956 return NULL;
1957 }
1958
paul22e0a9e2003-07-11 17:55:46 +00001959#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001960 if (CMD_IPV6 (dst))
1961 {
1962 if (cmd_ipv6_match (src))
1963 return dst;
1964 else
1965 return NULL;
1966 }
1967
1968 if (CMD_IPV6_PREFIX (dst))
1969 {
1970 if (cmd_ipv6_prefix_match (src))
1971 return dst;
1972 else
1973 return NULL;
1974 }
paul22e0a9e2003-07-11 17:55:46 +00001975#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001976
1977 if (CMD_IPV4 (dst))
1978 {
1979 if (cmd_ipv4_match (src))
1980 return dst;
1981 else
1982 return NULL;
1983 }
1984
1985 if (CMD_IPV4_PREFIX (dst))
1986 {
1987 if (cmd_ipv4_prefix_match (src))
1988 return dst;
1989 else
1990 return NULL;
1991 }
1992
1993 /* Optional or variable commands always match on '?' */
1994 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1995 return dst;
1996
1997 /* In case of 'command \t', given src is NULL string. */
1998 if (src == NULL)
1999 return dst;
2000
2001 if (strncmp (src, dst, strlen (src)) == 0)
2002 return dst;
2003 else
2004 return NULL;
2005}
2006
Christian Frankecd40b322013-09-30 12:27:51 +00002007/**
2008 * Check whether a string is already present in a vector of strings.
2009 * @param v A vector of char*.
2010 * @param str A char*.
2011 * @return 0 if str is already present in the vector, 1 otherwise.
2012 */
ajs274a4a42004-12-07 15:39:31 +00002013static int
hasso8c328f12004-10-05 21:01:23 +00002014cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00002015{
hasso8c328f12004-10-05 21:01:23 +00002016 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002017 char *match;
2018
paul55468c82005-03-14 20:19:01 +00002019 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00002020 if ((match = vector_slot (v, i)) != NULL)
2021 if (strcmp (match, str) == 0)
2022 return 0;
2023 return 1;
2024}
2025
Christian Frankecd40b322013-09-30 12:27:51 +00002026/**
2027 * Check whether a struct cmd_token matching a given string is already
2028 * present in a vector of struct cmd_token.
2029 * @param v A vector of struct cmd_token*.
2030 * @param str A char* which should be searched for.
2031 * @return 0 if there is a struct cmd_token* with its cmd matching str,
2032 * 1 otherwise.
2033 */
ajs274a4a42004-12-07 15:39:31 +00002034static int
hasso8c328f12004-10-05 21:01:23 +00002035desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00002036{
hasso8c328f12004-10-05 21:01:23 +00002037 unsigned int i;
Christian Frankecd40b322013-09-30 12:27:51 +00002038 struct cmd_token *token;
paul718e3742002-12-13 20:15:29 +00002039
paul55468c82005-03-14 20:19:01 +00002040 for (i = 0; i < vector_active (v); i++)
Christian Frankecd40b322013-09-30 12:27:51 +00002041 if ((token = vector_slot (v, i)) != NULL)
2042 if (strcmp (token->cmd, str) == 0)
2043 return 0;
2044 return 1;
paul718e3742002-12-13 20:15:29 +00002045}
2046
ajs274a4a42004-12-07 15:39:31 +00002047static int
paulb92938a2002-12-13 21:20:42 +00002048cmd_try_do_shortcut (enum node_type node, char* first_word) {
2049 if ( first_word != NULL &&
2050 node != AUTH_NODE &&
2051 node != VIEW_NODE &&
2052 node != AUTH_ENABLE_NODE &&
2053 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01002054 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00002055 0 == strcmp( "do", first_word ) )
2056 return 1;
2057 return 0;
2058}
2059
Christian Frankecd40b322013-09-30 12:27:51 +00002060static void
2061cmd_matches_free(vector *matches)
2062{
2063 unsigned int i;
2064 vector cmd_matches;
2065
2066 for (i = 0; i < vector_active(*matches); i++)
2067 if ((cmd_matches = vector_slot(*matches, i)) != NULL)
2068 vector_free(cmd_matches);
2069 vector_free(*matches);
2070 *matches = NULL;
2071}
2072
2073static int
2074cmd_describe_cmp(const void *a, const void *b)
2075{
2076 const struct cmd_token *first = *(struct cmd_token * const *)a;
2077 const struct cmd_token *second = *(struct cmd_token * const *)b;
2078
2079 return strcmp(first->cmd, second->cmd);
2080}
2081
2082static void
2083cmd_describe_sort(vector matchvec)
2084{
2085 qsort(matchvec->index, vector_active(matchvec),
2086 sizeof(void*), cmd_describe_cmp);
2087}
2088
paul718e3742002-12-13 20:15:29 +00002089/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00002090static vector
paulb92938a2002-12-13 21:20:42 +00002091cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00002092{
paulb8961472005-03-14 17:35:52 +00002093 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002094 vector cmd_vector;
2095#define INIT_MATCHVEC_SIZE 10
2096 vector matchvec;
2097 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00002098 unsigned int index;
paul54aba542003-08-21 20:28:24 +00002099 int ret;
2100 enum match_type match;
2101 char *command;
Christian Frankecd40b322013-09-30 12:27:51 +00002102 vector matches = NULL;
2103 vector match_vector;
paul718e3742002-12-13 20:15:29 +00002104
2105 /* Set index. */
paul55468c82005-03-14 20:19:01 +00002106 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00002107 {
2108 *status = CMD_ERR_NO_MATCH;
2109 return NULL;
2110 }
Christian Frankecd40b322013-09-30 12:27:51 +00002111
2112 index = vector_active (vline) - 1;
2113
paul718e3742002-12-13 20:15:29 +00002114 /* Make copy vector of current node's command vector. */
2115 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2116
2117 /* Prepare match vector */
2118 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2119
Christian Frankecd40b322013-09-30 12:27:51 +00002120 /* Filter commands and build a list how they could possibly continue. */
2121 for (i = 0; i <= index; i++)
2122 {
2123 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00002124
Christian Frankecd40b322013-09-30 12:27:51 +00002125 if (matches)
2126 cmd_matches_free(&matches);
paul718e3742002-12-13 20:15:29 +00002127
Christian Frankecd40b322013-09-30 12:27:51 +00002128 ret = cmd_vector_filter(cmd_vector,
2129 FILTER_RELAXED,
2130 vline, i,
2131 &match,
2132 &matches);
paul718e3742002-12-13 20:15:29 +00002133
Christian Frankecd40b322013-09-30 12:27:51 +00002134 if (ret != CMD_SUCCESS)
2135 {
2136 vector_free (cmd_vector);
2137 vector_free (matchvec);
2138 cmd_matches_free(&matches);
2139 *status = ret;
2140 return NULL;
2141 }
paul718e3742002-12-13 20:15:29 +00002142
Christian Frankecd40b322013-09-30 12:27:51 +00002143 /* The last match may well be ambigious, so break here */
2144 if (i == index)
2145 break;
paul718e3742002-12-13 20:15:29 +00002146
Christian Frankecd40b322013-09-30 12:27:51 +00002147 if (match == vararg_match)
2148 {
2149 /* We found a vararg match - so we can throw out the current matches here
2150 * and don't need to continue checking the command input */
2151 unsigned int j, k;
2152
2153 for (j = 0; j < vector_active (matches); j++)
2154 if ((match_vector = vector_slot (matches, j)) != NULL)
2155 for (k = 0; k < vector_active (match_vector); k++)
2156 {
2157 struct cmd_token *token = vector_slot (match_vector, k);
2158 vector_set (matchvec, token);
2159 }
2160
2161 *status = CMD_SUCCESS;
2162 vector_set(matchvec, &token_cr);
2163 vector_free (cmd_vector);
2164 cmd_matches_free(&matches);
2165 cmd_describe_sort(matchvec);
2166 return matchvec;
2167 }
2168
2169 ret = is_cmd_ambiguous(cmd_vector, command, matches, match);
2170 if (ret == 1)
2171 {
2172 vector_free (cmd_vector);
2173 vector_free (matchvec);
2174 cmd_matches_free(&matches);
2175 *status = CMD_ERR_AMBIGUOUS;
2176 return NULL;
2177 }
2178 else if (ret == 2)
2179 {
2180 vector_free (cmd_vector);
2181 vector_free (matchvec);
2182 cmd_matches_free(&matches);
2183 *status = CMD_ERR_NO_MATCH;
2184 return NULL;
2185 }
2186 }
paul54aba542003-08-21 20:28:24 +00002187
paul718e3742002-12-13 20:15:29 +00002188 /* Make description vector. */
Christian Frankecd40b322013-09-30 12:27:51 +00002189 for (i = 0; i < vector_active (matches); i++)
paul718e3742002-12-13 20:15:29 +00002190 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
2191 {
Christian Frankecd40b322013-09-30 12:27:51 +00002192 unsigned int j;
2193 const char *last_word;
2194 vector vline_trimmed;
paul718e3742002-12-13 20:15:29 +00002195
Christian Frankecd40b322013-09-30 12:27:51 +00002196 last_word = vector_slot(vline, vector_active(vline) - 1);
2197 if (last_word == NULL || !strlen(last_word))
2198 {
2199 vline_trimmed = vector_copy(vline);
2200 vector_unset(vline_trimmed, vector_active(vline_trimmed) - 1);
paul718e3742002-12-13 20:15:29 +00002201
Christian Frankecd40b322013-09-30 12:27:51 +00002202 if (cmd_is_complete(cmd_element, vline_trimmed)
2203 && desc_unique_string(matchvec, command_cr))
2204 {
2205 if (match != vararg_match)
2206 vector_set(matchvec, &token_cr);
2207 }
Chris Caputo228da422009-07-18 05:44:03 +00002208
Christian Frankecd40b322013-09-30 12:27:51 +00002209 vector_free(vline_trimmed);
2210 }
2211
2212 match_vector = vector_slot (matches, i);
2213 if (match_vector)
2214 for (j = 0; j < vector_active(match_vector); j++)
2215 {
2216 struct cmd_token *token = vector_slot(match_vector, j);
2217 const char *string;
2218
2219 string = cmd_entry_function_desc(command, token->cmd);
2220 if (string && desc_unique_string(matchvec, string))
2221 vector_set(matchvec, token);
2222 }
paul718e3742002-12-13 20:15:29 +00002223 }
2224 vector_free (cmd_vector);
Christian Frankecd40b322013-09-30 12:27:51 +00002225 cmd_matches_free(&matches);
paul718e3742002-12-13 20:15:29 +00002226
2227 if (vector_slot (matchvec, 0) == NULL)
2228 {
2229 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00002230 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00002231 return NULL;
paul718e3742002-12-13 20:15:29 +00002232 }
paul718e3742002-12-13 20:15:29 +00002233
Paul Jakma5fc60512006-05-12 23:24:09 +00002234 *status = CMD_SUCCESS;
Christian Frankecd40b322013-09-30 12:27:51 +00002235 cmd_describe_sort(matchvec);
paul718e3742002-12-13 20:15:29 +00002236 return matchvec;
2237}
2238
paulb92938a2002-12-13 21:20:42 +00002239vector
2240cmd_describe_command (vector vline, struct vty *vty, int *status)
2241{
2242 vector ret;
2243
2244 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2245 {
2246 enum node_type onode;
2247 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002248 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002249
2250 onode = vty->node;
2251 vty->node = ENABLE_NODE;
2252 /* We can try it on enable node, cos' the vty is authenticated */
2253
2254 shifted_vline = vector_init (vector_count(vline));
2255 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002256 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002257 {
2258 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2259 }
2260
2261 ret = cmd_describe_command_real (shifted_vline, vty, status);
2262
2263 vector_free(shifted_vline);
2264 vty->node = onode;
2265 return ret;
2266 }
2267
2268
2269 return cmd_describe_command_real (vline, vty, status);
2270}
2271
2272
paul718e3742002-12-13 20:15:29 +00002273/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00002274static int
paul718e3742002-12-13 20:15:29 +00002275cmd_lcd (char **matched)
2276{
2277 int i;
2278 int j;
2279 int lcd = -1;
2280 char *s1, *s2;
2281 char c1, c2;
2282
2283 if (matched[0] == NULL || matched[1] == NULL)
2284 return 0;
2285
2286 for (i = 1; matched[i] != NULL; i++)
2287 {
2288 s1 = matched[i - 1];
2289 s2 = matched[i];
2290
2291 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
2292 if (c1 != c2)
2293 break;
2294
2295 if (lcd < 0)
2296 lcd = j;
2297 else
2298 {
2299 if (lcd > j)
2300 lcd = j;
2301 }
2302 }
2303 return lcd;
2304}
2305
Christian Frankecd40b322013-09-30 12:27:51 +00002306static int
2307cmd_complete_cmp(const void *a, const void *b)
2308{
2309 const char *first = *(char * const *)a;
2310 const char *second = *(char * const *)b;
2311
2312 if (!first)
2313 {
2314 if (!second)
2315 return 0;
2316 return 1;
2317 }
2318 if (!second)
2319 return -1;
2320
2321 return strcmp(first, second);
2322}
2323
2324static void
2325cmd_complete_sort(vector matchvec)
2326{
2327 qsort(matchvec->index, vector_active(matchvec),
2328 sizeof(void*), cmd_complete_cmp);
2329}
2330
paul718e3742002-12-13 20:15:29 +00002331/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00002332static char **
paulb92938a2002-12-13 21:20:42 +00002333cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00002334{
paulb8961472005-03-14 17:35:52 +00002335 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002336 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2337#define INIT_MATCHVEC_SIZE 10
2338 vector matchvec;
paulb8961472005-03-14 17:35:52 +00002339 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002340 char **match_str;
Christian Frankecd40b322013-09-30 12:27:51 +00002341 struct cmd_token *token;
paul718e3742002-12-13 20:15:29 +00002342 char *command;
2343 int lcd;
Christian Frankecd40b322013-09-30 12:27:51 +00002344 vector matches = NULL;
2345 vector match_vector;
paul718e3742002-12-13 20:15:29 +00002346
paul55468c82005-03-14 20:19:01 +00002347 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00002348 {
Paul Jakmad2519962006-05-12 23:19:37 +00002349 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00002350 *status = CMD_ERR_NO_MATCH;
2351 return NULL;
2352 }
2353 else
paul55468c82005-03-14 20:19:01 +00002354 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00002355
Christian Frankecd40b322013-09-30 12:27:51 +00002356 /* First, filter by command string */
2357 for (i = 0; i <= index; i++)
2358 {
2359 command = vector_slot (vline, i);
2360 enum match_type match;
2361 int ret;
paul718e3742002-12-13 20:15:29 +00002362
Christian Frankecd40b322013-09-30 12:27:51 +00002363 if (matches)
2364 cmd_matches_free(&matches);
paul718e3742002-12-13 20:15:29 +00002365
Christian Frankecd40b322013-09-30 12:27:51 +00002366 /* First try completion match, if there is exactly match return 1 */
2367 ret = cmd_vector_filter(cmd_vector,
2368 FILTER_RELAXED,
2369 vline, i,
2370 &match,
2371 &matches);
2372
2373 if (ret != CMD_SUCCESS)
2374 {
2375 vector_free(cmd_vector);
2376 cmd_matches_free(&matches);
2377 *status = ret;
2378 return NULL;
2379 }
2380
2381 /* Break here - the completion mustn't be checked to be non-ambiguous */
2382 if (i == index)
2383 break;
2384
2385 /* If there is exact match then filter ambiguous match else check
2386 ambiguousness. */
2387 ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2388 if (ret == 1)
2389 {
2390 vector_free (cmd_vector);
2391 cmd_matches_free(&matches);
2392 *status = CMD_ERR_AMBIGUOUS;
2393 return NULL;
2394 }
2395 /*
paul909a2152005-03-14 17:41:45 +00002396 else if (ret == 2)
2397 {
2398 vector_free (cmd_vector);
Christian Frankecd40b322013-09-30 12:27:51 +00002399 cmd_matches_free(&matches);
paul909a2152005-03-14 17:41:45 +00002400 *status = CMD_ERR_NO_MATCH;
2401 return NULL;
2402 }
2403 */
Christian Frankecd40b322013-09-30 12:27:51 +00002404 }
paul909a2152005-03-14 17:41:45 +00002405
paul718e3742002-12-13 20:15:29 +00002406 /* Prepare match vector. */
2407 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2408
Christian Frankecd40b322013-09-30 12:27:51 +00002409 /* Build the possible list of continuations into a list of completions */
2410 for (i = 0; i < vector_active (matches); i++)
2411 if ((match_vector = vector_slot (matches, i)))
paul718e3742002-12-13 20:15:29 +00002412 {
hasso8c328f12004-10-05 21:01:23 +00002413 const char *string;
Christian Frankecd40b322013-09-30 12:27:51 +00002414 unsigned int j;
paul909a2152005-03-14 17:41:45 +00002415
Christian Frankecd40b322013-09-30 12:27:51 +00002416 for (j = 0; j < vector_active (match_vector); j++)
2417 if ((token = vector_slot (match_vector, j)))
paul909a2152005-03-14 17:41:45 +00002418 {
paulb8961472005-03-14 17:35:52 +00002419 if ((string =
2420 cmd_entry_function (vector_slot (vline, index),
Christian Frankecd40b322013-09-30 12:27:51 +00002421 token->cmd)))
paul909a2152005-03-14 17:41:45 +00002422 if (cmd_unique_string (matchvec, string))
2423 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
2424 }
paul718e3742002-12-13 20:15:29 +00002425 }
2426
2427 /* We don't need cmd_vector any more. */
2428 vector_free (cmd_vector);
Christian Frankecd40b322013-09-30 12:27:51 +00002429 cmd_matches_free(&matches);
paul718e3742002-12-13 20:15:29 +00002430
2431 /* No matched command */
2432 if (vector_slot (matchvec, 0) == NULL)
2433 {
2434 vector_free (matchvec);
2435
2436 /* In case of 'command \t' pattern. Do you need '?' command at
2437 the end of the line. */
2438 if (vector_slot (vline, index) == '\0')
2439 *status = CMD_ERR_NOTHING_TODO;
2440 else
2441 *status = CMD_ERR_NO_MATCH;
2442 return NULL;
2443 }
2444
2445 /* Only one matched */
2446 if (vector_slot (matchvec, 1) == NULL)
2447 {
2448 match_str = (char **) matchvec->index;
2449 vector_only_wrapper_free (matchvec);
2450 *status = CMD_COMPLETE_FULL_MATCH;
2451 return match_str;
2452 }
2453 /* Make it sure last element is NULL. */
2454 vector_set (matchvec, NULL);
2455
2456 /* Check LCD of matched strings. */
2457 if (vector_slot (vline, index) != NULL)
2458 {
2459 lcd = cmd_lcd ((char **) matchvec->index);
2460
2461 if (lcd)
2462 {
2463 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00002464
paul718e3742002-12-13 20:15:29 +00002465 if (len < lcd)
2466 {
2467 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00002468
Christian Frankecd40b322013-09-30 12:27:51 +00002469 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
paul718e3742002-12-13 20:15:29 +00002470 memcpy (lcdstr, matchvec->index[0], lcd);
2471 lcdstr[lcd] = '\0';
2472
2473 /* match_str = (char **) &lcdstr; */
2474
2475 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00002476 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00002477 {
2478 if (vector_slot (matchvec, i))
Christian Frankecd40b322013-09-30 12:27:51 +00002479 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00002480 }
2481 vector_free (matchvec);
2482
paul909a2152005-03-14 17:41:45 +00002483 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00002484 matchvec = vector_init (INIT_MATCHVEC_SIZE);
2485 vector_set (matchvec, lcdstr);
2486 match_str = (char **) matchvec->index;
2487 vector_only_wrapper_free (matchvec);
2488
2489 *status = CMD_COMPLETE_MATCH;
2490 return match_str;
2491 }
2492 }
2493 }
2494
2495 match_str = (char **) matchvec->index;
Christian Frankecd40b322013-09-30 12:27:51 +00002496 cmd_complete_sort(matchvec);
paul718e3742002-12-13 20:15:29 +00002497 vector_only_wrapper_free (matchvec);
2498 *status = CMD_COMPLETE_LIST_MATCH;
2499 return match_str;
2500}
2501
paulb92938a2002-12-13 21:20:42 +00002502char **
paul9ab68122003-01-18 01:16:20 +00002503cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00002504{
2505 char **ret;
2506
2507 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2508 {
2509 enum node_type onode;
2510 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002511 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002512
2513 onode = vty->node;
2514 vty->node = ENABLE_NODE;
2515 /* We can try it on enable node, cos' the vty is authenticated */
2516
2517 shifted_vline = vector_init (vector_count(vline));
2518 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002519 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002520 {
2521 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2522 }
2523
2524 ret = cmd_complete_command_real (shifted_vline, vty, status);
2525
2526 vector_free(shifted_vline);
2527 vty->node = onode;
2528 return ret;
2529 }
2530
2531
2532 return cmd_complete_command_real (vline, vty, status);
2533}
2534
2535/* return parent node */
2536/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00002537enum node_type
ajs274a4a42004-12-07 15:39:31 +00002538node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00002539{
2540 enum node_type ret;
2541
paul9ab68122003-01-18 01:16:20 +00002542 assert (node > CONFIG_NODE);
2543
2544 switch (node)
2545 {
2546 case BGP_VPNV4_NODE:
2547 case BGP_IPV4_NODE:
2548 case BGP_IPV4M_NODE:
2549 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002550 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00002551 ret = BGP_NODE;
2552 break;
2553 case KEYCHAIN_KEY_NODE:
2554 ret = KEYCHAIN_NODE;
2555 break;
2556 default:
2557 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00002558 }
2559
2560 return ret;
2561}
2562
paul718e3742002-12-13 20:15:29 +00002563/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00002564static int
Christian Frankecd40b322013-09-30 12:27:51 +00002565cmd_execute_command_real (vector vline,
2566 enum filter_type filter,
2567 struct vty *vty,
paulb8961472005-03-14 17:35:52 +00002568 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00002569{
hasso8c328f12004-10-05 21:01:23 +00002570 unsigned int i;
2571 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002572 vector cmd_vector;
2573 struct cmd_element *cmd_element;
2574 struct cmd_element *matched_element;
2575 unsigned int matched_count, incomplete_count;
2576 int argc;
paul9035efa2004-10-10 11:56:56 +00002577 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002578 enum match_type match = 0;
paul718e3742002-12-13 20:15:29 +00002579 char *command;
Christian Frankecd40b322013-09-30 12:27:51 +00002580 int ret;
2581 vector matches;
paul718e3742002-12-13 20:15:29 +00002582
2583 /* Make copy of command elements. */
2584 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2585
paul55468c82005-03-14 20:19:01 +00002586 for (index = 0; index < vector_active (vline); index++)
Christian Frankecd40b322013-09-30 12:27:51 +00002587 {
2588 command = vector_slot (vline, index);
2589 ret = cmd_vector_filter(cmd_vector,
2590 filter,
2591 vline, index,
2592 &match,
2593 &matches);
paul718e3742002-12-13 20:15:29 +00002594
Christian Frankecd40b322013-09-30 12:27:51 +00002595 if (ret != CMD_SUCCESS)
2596 {
2597 cmd_matches_free(&matches);
2598 return ret;
2599 }
paul718e3742002-12-13 20:15:29 +00002600
Christian Frankecd40b322013-09-30 12:27:51 +00002601 if (match == vararg_match)
2602 {
2603 cmd_matches_free(&matches);
paul909a2152005-03-14 17:41:45 +00002604 break;
Christian Frankecd40b322013-09-30 12:27:51 +00002605 }
paul718e3742002-12-13 20:15:29 +00002606
Christian Frankecd40b322013-09-30 12:27:51 +00002607 ret = is_cmd_ambiguous (cmd_vector, command, matches, match);
2608 cmd_matches_free(&matches);
2609
2610 if (ret == 1)
2611 {
2612 vector_free(cmd_vector);
2613 return CMD_ERR_AMBIGUOUS;
2614 }
2615 else if (ret == 2)
2616 {
2617 vector_free(cmd_vector);
2618 return CMD_ERR_NO_MATCH;
2619 }
2620 }
paul718e3742002-12-13 20:15:29 +00002621
2622 /* Check matched count. */
2623 matched_element = NULL;
2624 matched_count = 0;
2625 incomplete_count = 0;
2626
paul55468c82005-03-14 20:19:01 +00002627 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002628 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002629 {
Christian Frankecd40b322013-09-30 12:27:51 +00002630 if (cmd_is_complete(cmd_element, vline))
paul718e3742002-12-13 20:15:29 +00002631 {
2632 matched_element = cmd_element;
paul718e3742002-12-13 20:15:29 +00002633 matched_count++;
2634 }
2635 else
2636 {
2637 incomplete_count++;
2638 }
2639 }
paul909a2152005-03-14 17:41:45 +00002640
paul718e3742002-12-13 20:15:29 +00002641 /* Finish of using cmd_vector. */
2642 vector_free (cmd_vector);
2643
paul909a2152005-03-14 17:41:45 +00002644 /* To execute command, matched_count must be 1. */
2645 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002646 {
2647 if (incomplete_count)
2648 return CMD_ERR_INCOMPLETE;
2649 else
2650 return CMD_ERR_NO_MATCH;
2651 }
2652
paul909a2152005-03-14 17:41:45 +00002653 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002654 return CMD_ERR_AMBIGUOUS;
2655
Christian Frankecd40b322013-09-30 12:27:51 +00002656 ret = cmd_parse(matched_element, vline, &argc, argv);
2657 if (ret != CMD_SUCCESS)
2658 return ret;
paul718e3742002-12-13 20:15:29 +00002659
2660 /* For vtysh execution. */
2661 if (cmd)
2662 *cmd = matched_element;
2663
2664 if (matched_element->daemon)
2665 return CMD_SUCCESS_DAEMON;
2666
2667 /* Execute matched command. */
2668 return (*matched_element->func) (matched_element, vty, argc, argv);
2669}
2670
Christian Frankecd40b322013-09-30 12:27:51 +00002671/**
2672 * Execute a given command, handling things like "do ..." and checking
2673 * whether the given command might apply at a parent node if doesn't
2674 * apply for the current node.
2675 *
2676 * @param vline Command line input, vector of char* where each element is
2677 * one input token.
2678 * @param vty The vty context in which the command should be executed.
2679 * @param cmd Pointer where the struct cmd_element of the matched command
2680 * will be stored, if any. May be set to NULL if this info is
2681 * not needed.
2682 * @param vtysh If set != 0, don't lookup the command at parent nodes.
2683 * @return The status of the command that has been executed or an error code
2684 * as to why no command could be executed.
2685 */
paulb92938a2002-12-13 21:20:42 +00002686int
hasso87d683b2005-01-16 23:31:54 +00002687cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2688 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002689 int ret, saved_ret, tried = 0;
2690 enum node_type onode, try_node;
2691
2692 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002693
2694 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2695 {
2696 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002697 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002698
2699 vty->node = ENABLE_NODE;
2700 /* We can try it on enable node, cos' the vty is authenticated */
2701
2702 shifted_vline = vector_init (vector_count(vline));
2703 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002704 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002705 {
2706 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2707 }
2708
Christian Frankecd40b322013-09-30 12:27:51 +00002709 ret = cmd_execute_command_real (shifted_vline, FILTER_RELAXED, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002710
2711 vector_free(shifted_vline);
2712 vty->node = onode;
2713 return ret;
2714 }
2715
2716
Christian Frankecd40b322013-09-30 12:27:51 +00002717 saved_ret = ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002718
hasso87d683b2005-01-16 23:31:54 +00002719 if (vtysh)
2720 return saved_ret;
2721
paulb92938a2002-12-13 21:20:42 +00002722 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002723 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002724 && vty->node > CONFIG_NODE )
2725 {
paul9ab68122003-01-18 01:16:20 +00002726 try_node = node_parent(try_node);
2727 vty->node = try_node;
Christian Frankecd40b322013-09-30 12:27:51 +00002728 ret = cmd_execute_command_real (vline, FILTER_RELAXED, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002729 tried = 1;
2730 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002731 {
paul9ab68122003-01-18 01:16:20 +00002732 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002733 return ret;
2734 }
paulb92938a2002-12-13 21:20:42 +00002735 }
paul9ab68122003-01-18 01:16:20 +00002736 /* no command succeeded, reset the vty to the original node and
2737 return the error for this node */
2738 if ( tried )
2739 vty->node = onode;
2740 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002741}
2742
Christian Frankecd40b322013-09-30 12:27:51 +00002743/**
2744 * Execute a given command, matching it strictly against the current node.
2745 * This mode is used when reading config files.
2746 *
2747 * @param vline Command line input, vector of char* where each element is
2748 * one input token.
2749 * @param vty The vty context in which the command should be executed.
2750 * @param cmd Pointer where the struct cmd_element* of the matched command
2751 * will be stored, if any. May be set to NULL if this info is
2752 * not needed.
2753 * @return The status of the command that has been executed or an error code
2754 * as to why no command could be executed.
2755 */
paul718e3742002-12-13 20:15:29 +00002756int
paul909a2152005-03-14 17:41:45 +00002757cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002758 struct cmd_element **cmd)
2759{
Christian Frankecd40b322013-09-30 12:27:51 +00002760 return cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd);
paul718e3742002-12-13 20:15:29 +00002761}
2762
2763/* Configration make from file. */
2764int
Steve Hillea555002009-07-28 16:36:14 -04002765config_from_file (struct vty *vty, FILE *fp, unsigned int *line_num)
paul718e3742002-12-13 20:15:29 +00002766{
2767 int ret;
Steve Hillea555002009-07-28 16:36:14 -04002768 *line_num = 0;
paul718e3742002-12-13 20:15:29 +00002769 vector vline;
2770
2771 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2772 {
Steve Hillea555002009-07-28 16:36:14 -04002773 ++(*line_num);
paul718e3742002-12-13 20:15:29 +00002774 vline = cmd_make_strvec (vty->buf);
2775
2776 /* In case of comment line */
2777 if (vline == NULL)
2778 continue;
2779 /* Execute configuration command : this is strict match */
2780 ret = cmd_execute_command_strict (vline, vty, NULL);
2781
2782 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002783 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002784 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2785 {
paulb92938a2002-12-13 21:20:42 +00002786 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002787 ret = cmd_execute_command_strict (vline, vty, NULL);
2788 }
paul9ab68122003-01-18 01:16:20 +00002789
paul718e3742002-12-13 20:15:29 +00002790 cmd_free_strvec (vline);
2791
hassoddd85ed2004-10-13 08:18:07 +00002792 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2793 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002794 return ret;
2795 }
2796 return CMD_SUCCESS;
2797}
2798
2799/* Configration from terminal */
2800DEFUN (config_terminal,
2801 config_terminal_cmd,
2802 "configure terminal",
2803 "Configuration from vty interface\n"
2804 "Configuration terminal\n")
2805{
2806 if (vty_config_lock (vty))
2807 vty->node = CONFIG_NODE;
2808 else
2809 {
2810 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2811 return CMD_WARNING;
2812 }
2813 return CMD_SUCCESS;
2814}
2815
2816/* Enable command */
2817DEFUN (enable,
2818 config_enable_cmd,
2819 "enable",
2820 "Turn on privileged mode command\n")
2821{
2822 /* If enable password is NULL, change to ENABLE_NODE */
2823 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2824 vty->type == VTY_SHELL_SERV)
2825 vty->node = ENABLE_NODE;
2826 else
2827 vty->node = AUTH_ENABLE_NODE;
2828
2829 return CMD_SUCCESS;
2830}
2831
2832/* Disable command */
2833DEFUN (disable,
2834 config_disable_cmd,
2835 "disable",
2836 "Turn off privileged mode command\n")
2837{
2838 if (vty->node == ENABLE_NODE)
2839 vty->node = VIEW_NODE;
2840 return CMD_SUCCESS;
2841}
2842
2843/* Down vty node level. */
2844DEFUN (config_exit,
2845 config_exit_cmd,
2846 "exit",
2847 "Exit current mode and down to previous mode\n")
2848{
2849 switch (vty->node)
2850 {
2851 case VIEW_NODE:
2852 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002853 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002854 if (vty_shell (vty))
2855 exit (0);
2856 else
2857 vty->status = VTY_CLOSE;
2858 break;
2859 case CONFIG_NODE:
2860 vty->node = ENABLE_NODE;
2861 vty_config_unlock (vty);
2862 break;
2863 case INTERFACE_NODE:
2864 case ZEBRA_NODE:
2865 case BGP_NODE:
2866 case RIP_NODE:
2867 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002868 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002869 case OSPF_NODE:
2870 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002871 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002872 case KEYCHAIN_NODE:
2873 case MASC_NODE:
2874 case RMAP_NODE:
Everton Marques42e30782009-11-18 17:19:43 -02002875 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +00002876 case VTY_NODE:
2877 vty->node = CONFIG_NODE;
2878 break;
2879 case BGP_VPNV4_NODE:
2880 case BGP_IPV4_NODE:
2881 case BGP_IPV4M_NODE:
2882 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002883 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002884 vty->node = BGP_NODE;
2885 break;
2886 case KEYCHAIN_KEY_NODE:
2887 vty->node = KEYCHAIN_NODE;
2888 break;
2889 default:
2890 break;
2891 }
2892 return CMD_SUCCESS;
2893}
2894
2895/* quit is alias of exit. */
2896ALIAS (config_exit,
2897 config_quit_cmd,
2898 "quit",
2899 "Exit current mode and down to previous mode\n")
2900
2901/* End of configuration. */
2902DEFUN (config_end,
2903 config_end_cmd,
2904 "end",
2905 "End current mode and change to enable mode.")
2906{
2907 switch (vty->node)
2908 {
2909 case VIEW_NODE:
2910 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002911 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002912 /* Nothing to do. */
2913 break;
2914 case CONFIG_NODE:
2915 case INTERFACE_NODE:
2916 case ZEBRA_NODE:
2917 case RIP_NODE:
2918 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002919 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002920 case BGP_NODE:
2921 case BGP_VPNV4_NODE:
2922 case BGP_IPV4_NODE:
2923 case BGP_IPV4M_NODE:
2924 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002925 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002926 case RMAP_NODE:
2927 case OSPF_NODE:
2928 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002929 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002930 case KEYCHAIN_NODE:
2931 case KEYCHAIN_KEY_NODE:
2932 case MASC_NODE:
Everton Marques42e30782009-11-18 17:19:43 -02002933 case PIM_NODE:
paul718e3742002-12-13 20:15:29 +00002934 case VTY_NODE:
2935 vty_config_unlock (vty);
2936 vty->node = ENABLE_NODE;
2937 break;
2938 default:
2939 break;
2940 }
2941 return CMD_SUCCESS;
2942}
2943
2944/* Show version. */
2945DEFUN (show_version,
2946 show_version_cmd,
2947 "show version",
2948 SHOW_STR
2949 "Displays zebra version\n")
2950{
hasso12f6ea22005-03-07 08:35:39 +00002951 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2952 VTY_NEWLINE);
David Lamparter0be793e2012-11-27 01:34:56 +00002953 vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002954
2955 return CMD_SUCCESS;
2956}
2957
2958/* Help display function for all node. */
2959DEFUN (config_help,
2960 config_help_cmd,
2961 "help",
2962 "Description of the interactive help system\n")
2963{
2964 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002965 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002966anytime at the command line please press '?'.%s\
2967%s\
2968If nothing matches, the help list will be empty and you must backup%s\
2969 until entering a '?' shows the available options.%s\
2970Two styles of help are provided:%s\
29711. Full help is available when you are ready to enter a%s\
2972command argument (e.g. 'show ?') and describes each possible%s\
2973argument.%s\
29742. Partial help is provided when an abbreviated argument is entered%s\
2975 and you want to know what arguments match the input%s\
2976 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2977 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2978 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2979 return CMD_SUCCESS;
2980}
2981
2982/* Help display function for all node. */
2983DEFUN (config_list,
2984 config_list_cmd,
2985 "list",
2986 "Print command list\n")
2987{
hasso8c328f12004-10-05 21:01:23 +00002988 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002989 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2990 struct cmd_element *cmd;
2991
paul55468c82005-03-14 20:19:01 +00002992 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002993 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2994 && !(cmd->attr == CMD_ATTR_DEPRECATED
2995 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002996 vty_out (vty, " %s%s", cmd->string,
2997 VTY_NEWLINE);
2998 return CMD_SUCCESS;
2999}
3000
3001/* Write current configuration into file. */
3002DEFUN (config_write_file,
3003 config_write_file_cmd,
3004 "write file",
3005 "Write running configuration to memory, network, or terminal\n"
3006 "Write to configuration file\n")
3007{
hasso8c328f12004-10-05 21:01:23 +00003008 unsigned int i;
paul718e3742002-12-13 20:15:29 +00003009 int fd;
3010 struct cmd_node *node;
3011 char *config_file;
3012 char *config_file_tmp = NULL;
3013 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00003014 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00003015 struct vty *file_vty;
3016
3017 /* Check and see if we are operating under vtysh configuration */
3018 if (host.config == NULL)
3019 {
3020 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
3021 VTY_NEWLINE);
3022 return CMD_WARNING;
3023 }
3024
3025 /* Get filename. */
3026 config_file = host.config;
3027
paul05865c92005-10-26 05:49:54 +00003028 config_file_sav =
3029 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00003030 strcpy (config_file_sav, config_file);
3031 strcat (config_file_sav, CONF_BACKUP_EXT);
3032
3033
paul05865c92005-10-26 05:49:54 +00003034 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00003035 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
3036
3037 /* Open file to configuration write. */
3038 fd = mkstemp (config_file_tmp);
3039 if (fd < 0)
3040 {
3041 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
3042 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003043 goto finished;
paul718e3742002-12-13 20:15:29 +00003044 }
3045
3046 /* Make vty for configuration file. */
3047 file_vty = vty_new ();
3048 file_vty->fd = fd;
3049 file_vty->type = VTY_FILE;
3050
3051 /* Config file header print. */
3052 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
3053 vty_time_print (file_vty, 1);
3054 vty_out (file_vty, "!\n");
3055
paul55468c82005-03-14 20:19:01 +00003056 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00003057 if ((node = vector_slot (cmdvec, i)) && node->func)
3058 {
3059 if ((*node->func) (file_vty))
3060 vty_out (file_vty, "!\n");
3061 }
3062 vty_close (file_vty);
3063
3064 if (unlink (config_file_sav) != 0)
3065 if (errno != ENOENT)
3066 {
3067 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
3068 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003069 goto finished;
paul718e3742002-12-13 20:15:29 +00003070 }
3071 if (link (config_file, config_file_sav) != 0)
3072 {
3073 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
3074 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003075 goto finished;
paul718e3742002-12-13 20:15:29 +00003076 }
3077 sync ();
3078 if (unlink (config_file) != 0)
3079 {
3080 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
3081 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003082 goto finished;
paul718e3742002-12-13 20:15:29 +00003083 }
3084 if (link (config_file_tmp, config_file) != 0)
3085 {
3086 vty_out (vty, "Can't save configuration file %s.%s", config_file,
3087 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003088 goto finished;
paul718e3742002-12-13 20:15:29 +00003089 }
paul718e3742002-12-13 20:15:29 +00003090 sync ();
3091
gdtaa593d52003-12-22 20:15:53 +00003092 if (chmod (config_file, CONFIGFILE_MASK) != 0)
3093 {
3094 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00003095 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003096 goto finished;
gdtaa593d52003-12-22 20:15:53 +00003097 }
3098
paul718e3742002-12-13 20:15:29 +00003099 vty_out (vty, "Configuration saved to %s%s", config_file,
3100 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00003101 ret = CMD_SUCCESS;
3102
3103finished:
3104 unlink (config_file_tmp);
3105 XFREE (MTYPE_TMP, config_file_tmp);
3106 XFREE (MTYPE_TMP, config_file_sav);
3107 return ret;
paul718e3742002-12-13 20:15:29 +00003108}
3109
3110ALIAS (config_write_file,
3111 config_write_cmd,
3112 "write",
3113 "Write running configuration to memory, network, or terminal\n")
3114
3115ALIAS (config_write_file,
3116 config_write_memory_cmd,
3117 "write memory",
3118 "Write running configuration to memory, network, or terminal\n"
3119 "Write configuration to the file (same as write file)\n")
3120
3121ALIAS (config_write_file,
3122 copy_runningconfig_startupconfig_cmd,
3123 "copy running-config startup-config",
3124 "Copy configuration\n"
3125 "Copy running config to... \n"
3126 "Copy running config to startup config (same as write file)\n")
3127
3128/* Write current configuration into the terminal. */
3129DEFUN (config_write_terminal,
3130 config_write_terminal_cmd,
3131 "write terminal",
3132 "Write running configuration to memory, network, or terminal\n"
3133 "Write to terminal\n")
3134{
hasso8c328f12004-10-05 21:01:23 +00003135 unsigned int i;
paul718e3742002-12-13 20:15:29 +00003136 struct cmd_node *node;
3137
3138 if (vty->type == VTY_SHELL_SERV)
3139 {
paul55468c82005-03-14 20:19:01 +00003140 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00003141 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
3142 {
3143 if ((*node->func) (vty))
3144 vty_out (vty, "!%s", VTY_NEWLINE);
3145 }
3146 }
3147 else
3148 {
3149 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
3150 VTY_NEWLINE);
3151 vty_out (vty, "!%s", VTY_NEWLINE);
3152
paul55468c82005-03-14 20:19:01 +00003153 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00003154 if ((node = vector_slot (cmdvec, i)) && node->func)
3155 {
3156 if ((*node->func) (vty))
3157 vty_out (vty, "!%s", VTY_NEWLINE);
3158 }
3159 vty_out (vty, "end%s",VTY_NEWLINE);
3160 }
3161 return CMD_SUCCESS;
3162}
3163
3164/* Write current configuration into the terminal. */
3165ALIAS (config_write_terminal,
3166 show_running_config_cmd,
3167 "show running-config",
3168 SHOW_STR
3169 "running configuration\n")
3170
3171/* Write startup configuration into the terminal. */
3172DEFUN (show_startup_config,
3173 show_startup_config_cmd,
3174 "show startup-config",
3175 SHOW_STR
3176 "Contentes of startup configuration\n")
3177{
3178 char buf[BUFSIZ];
3179 FILE *confp;
3180
3181 confp = fopen (host.config, "r");
3182 if (confp == NULL)
3183 {
3184 vty_out (vty, "Can't open configuration file [%s]%s",
3185 host.config, VTY_NEWLINE);
3186 return CMD_WARNING;
3187 }
3188
3189 while (fgets (buf, BUFSIZ, confp))
3190 {
3191 char *cp = buf;
3192
3193 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
3194 cp++;
3195 *cp = '\0';
3196
3197 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
3198 }
3199
3200 fclose (confp);
3201
3202 return CMD_SUCCESS;
3203}
3204
3205/* Hostname configuration */
3206DEFUN (config_hostname,
3207 hostname_cmd,
3208 "hostname WORD",
3209 "Set system's network name\n"
3210 "This system's network name\n")
3211{
3212 if (!isalpha((int) *argv[0]))
3213 {
3214 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
3215 return CMD_WARNING;
3216 }
3217
3218 if (host.name)
paul05865c92005-10-26 05:49:54 +00003219 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00003220
paul05865c92005-10-26 05:49:54 +00003221 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00003222 return CMD_SUCCESS;
3223}
3224
3225DEFUN (config_no_hostname,
3226 no_hostname_cmd,
3227 "no hostname [HOSTNAME]",
3228 NO_STR
3229 "Reset system's network name\n"
3230 "Host name of this router\n")
3231{
3232 if (host.name)
paul05865c92005-10-26 05:49:54 +00003233 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00003234 host.name = NULL;
3235 return CMD_SUCCESS;
3236}
3237
3238/* VTY interface password set. */
3239DEFUN (config_password, password_cmd,
3240 "password (8|) WORD",
3241 "Assign the terminal connection password\n"
3242 "Specifies a HIDDEN password will follow\n"
3243 "dummy string \n"
3244 "The HIDDEN line password string\n")
3245{
3246 /* Argument check. */
3247 if (argc == 0)
3248 {
3249 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3250 return CMD_WARNING;
3251 }
3252
3253 if (argc == 2)
3254 {
3255 if (*argv[0] == '8')
3256 {
3257 if (host.password)
paul05865c92005-10-26 05:49:54 +00003258 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00003259 host.password = NULL;
3260 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00003261 XFREE (MTYPE_HOST, host.password_encrypt);
3262 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00003263 return CMD_SUCCESS;
3264 }
3265 else
3266 {
3267 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3268 return CMD_WARNING;
3269 }
3270 }
3271
3272 if (!isalnum ((int) *argv[0]))
3273 {
3274 vty_out (vty,
3275 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3276 return CMD_WARNING;
3277 }
3278
3279 if (host.password)
paul05865c92005-10-26 05:49:54 +00003280 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00003281 host.password = NULL;
3282
3283 if (host.encrypt)
3284 {
3285 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00003286 XFREE (MTYPE_HOST, host.password_encrypt);
3287 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00003288 }
3289 else
paul05865c92005-10-26 05:49:54 +00003290 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00003291
3292 return CMD_SUCCESS;
3293}
3294
3295ALIAS (config_password, password_text_cmd,
3296 "password LINE",
3297 "Assign the terminal connection password\n"
3298 "The UNENCRYPTED (cleartext) line password\n")
3299
3300/* VTY enable password set. */
3301DEFUN (config_enable_password, enable_password_cmd,
3302 "enable password (8|) WORD",
3303 "Modify enable password parameters\n"
3304 "Assign the privileged level password\n"
3305 "Specifies a HIDDEN password will follow\n"
3306 "dummy string \n"
3307 "The HIDDEN 'enable' password string\n")
3308{
3309 /* Argument check. */
3310 if (argc == 0)
3311 {
3312 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
3313 return CMD_WARNING;
3314 }
3315
3316 /* Crypt type is specified. */
3317 if (argc == 2)
3318 {
3319 if (*argv[0] == '8')
3320 {
3321 if (host.enable)
paul05865c92005-10-26 05:49:54 +00003322 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00003323 host.enable = NULL;
3324
3325 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00003326 XFREE (MTYPE_HOST, host.enable_encrypt);
3327 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00003328
3329 return CMD_SUCCESS;
3330 }
3331 else
3332 {
3333 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
3334 return CMD_WARNING;
3335 }
3336 }
3337
3338 if (!isalnum ((int) *argv[0]))
3339 {
3340 vty_out (vty,
3341 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
3342 return CMD_WARNING;
3343 }
3344
3345 if (host.enable)
paul05865c92005-10-26 05:49:54 +00003346 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00003347 host.enable = NULL;
3348
3349 /* Plain password input. */
3350 if (host.encrypt)
3351 {
3352 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00003353 XFREE (MTYPE_HOST, host.enable_encrypt);
3354 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00003355 }
3356 else
paul05865c92005-10-26 05:49:54 +00003357 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00003358
3359 return CMD_SUCCESS;
3360}
3361
3362ALIAS (config_enable_password,
3363 enable_password_text_cmd,
3364 "enable password LINE",
3365 "Modify enable password parameters\n"
3366 "Assign the privileged level password\n"
3367 "The UNENCRYPTED (cleartext) 'enable' password\n")
3368
3369/* VTY enable password delete. */
3370DEFUN (no_config_enable_password, no_enable_password_cmd,
3371 "no enable password",
3372 NO_STR
3373 "Modify enable password parameters\n"
3374 "Assign the privileged level password\n")
3375{
3376 if (host.enable)
paul05865c92005-10-26 05:49:54 +00003377 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00003378 host.enable = NULL;
3379
3380 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00003381 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00003382 host.enable_encrypt = NULL;
3383
3384 return CMD_SUCCESS;
3385}
3386
3387DEFUN (service_password_encrypt,
3388 service_password_encrypt_cmd,
3389 "service password-encryption",
3390 "Set up miscellaneous service\n"
3391 "Enable encrypted passwords\n")
3392{
3393 if (host.encrypt)
3394 return CMD_SUCCESS;
3395
3396 host.encrypt = 1;
3397
3398 if (host.password)
3399 {
3400 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00003401 XFREE (MTYPE_HOST, host.password_encrypt);
3402 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00003403 }
3404 if (host.enable)
3405 {
3406 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00003407 XFREE (MTYPE_HOST, host.enable_encrypt);
3408 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00003409 }
3410
3411 return CMD_SUCCESS;
3412}
3413
3414DEFUN (no_service_password_encrypt,
3415 no_service_password_encrypt_cmd,
3416 "no service password-encryption",
3417 NO_STR
3418 "Set up miscellaneous service\n"
3419 "Enable encrypted passwords\n")
3420{
3421 if (! host.encrypt)
3422 return CMD_SUCCESS;
3423
3424 host.encrypt = 0;
3425
3426 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00003427 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00003428 host.password_encrypt = NULL;
3429
3430 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00003431 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00003432 host.enable_encrypt = NULL;
3433
3434 return CMD_SUCCESS;
3435}
3436
3437DEFUN (config_terminal_length, config_terminal_length_cmd,
3438 "terminal length <0-512>",
3439 "Set terminal line parameters\n"
3440 "Set number of lines on a screen\n"
3441 "Number of lines on screen (0 for no pausing)\n")
3442{
3443 int lines;
3444 char *endptr = NULL;
3445
3446 lines = strtol (argv[0], &endptr, 10);
3447 if (lines < 0 || lines > 512 || *endptr != '\0')
3448 {
3449 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3450 return CMD_WARNING;
3451 }
3452 vty->lines = lines;
3453
3454 return CMD_SUCCESS;
3455}
3456
3457DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
3458 "terminal no length",
3459 "Set terminal line parameters\n"
3460 NO_STR
3461 "Set number of lines on a screen\n")
3462{
3463 vty->lines = -1;
3464 return CMD_SUCCESS;
3465}
3466
3467DEFUN (service_terminal_length, service_terminal_length_cmd,
3468 "service terminal-length <0-512>",
3469 "Set up miscellaneous service\n"
3470 "System wide terminal length configuration\n"
3471 "Number of lines of VTY (0 means no line control)\n")
3472{
3473 int lines;
3474 char *endptr = NULL;
3475
3476 lines = strtol (argv[0], &endptr, 10);
3477 if (lines < 0 || lines > 512 || *endptr != '\0')
3478 {
3479 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3480 return CMD_WARNING;
3481 }
3482 host.lines = lines;
3483
3484 return CMD_SUCCESS;
3485}
3486
3487DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3488 "no service terminal-length [<0-512>]",
3489 NO_STR
3490 "Set up miscellaneous service\n"
3491 "System wide terminal length configuration\n"
3492 "Number of lines of VTY (0 means no line control)\n")
3493{
3494 host.lines = -1;
3495 return CMD_SUCCESS;
3496}
3497
ajs2885f722004-12-17 23:16:33 +00003498DEFUN_HIDDEN (do_echo,
3499 echo_cmd,
3500 "echo .MESSAGE",
3501 "Echo a message back to the vty\n"
3502 "The message to echo\n")
3503{
3504 char *message;
3505
ajsf6834d42005-01-28 20:28:35 +00003506 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3507 VTY_NEWLINE);
3508 if (message)
3509 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003510 return CMD_SUCCESS;
3511}
3512
ajs274a4a42004-12-07 15:39:31 +00003513DEFUN (config_logmsg,
3514 config_logmsg_cmd,
3515 "logmsg "LOG_LEVELS" .MESSAGE",
3516 "Send a message to enabled logging destinations\n"
3517 LOG_LEVEL_DESC
3518 "The message to send\n")
3519{
3520 int level;
3521 char *message;
3522
3523 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3524 return CMD_ERR_NO_MATCH;
3525
Christian Hammersfc951862011-03-23 13:07:55 +03003526 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
ajsf6834d42005-01-28 20:28:35 +00003527 if (message)
3528 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003529 return CMD_SUCCESS;
3530}
3531
3532DEFUN (show_logging,
3533 show_logging_cmd,
3534 "show logging",
3535 SHOW_STR
3536 "Show current logging configuration\n")
3537{
3538 struct zlog *zl = zlog_default;
3539
3540 vty_out (vty, "Syslog logging: ");
3541 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3542 vty_out (vty, "disabled");
3543 else
3544 vty_out (vty, "level %s, facility %s, ident %s",
3545 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3546 facility_name(zl->facility), zl->ident);
3547 vty_out (vty, "%s", VTY_NEWLINE);
3548
3549 vty_out (vty, "Stdout logging: ");
3550 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3551 vty_out (vty, "disabled");
3552 else
3553 vty_out (vty, "level %s",
3554 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3555 vty_out (vty, "%s", VTY_NEWLINE);
3556
3557 vty_out (vty, "Monitor logging: ");
3558 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3559 vty_out (vty, "disabled");
3560 else
3561 vty_out (vty, "level %s",
3562 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3563 vty_out (vty, "%s", VTY_NEWLINE);
3564
3565 vty_out (vty, "File logging: ");
3566 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3567 !zl->fp)
3568 vty_out (vty, "disabled");
3569 else
3570 vty_out (vty, "level %s, filename %s",
3571 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3572 zl->filename);
3573 vty_out (vty, "%s", VTY_NEWLINE);
3574
3575 vty_out (vty, "Protocol name: %s%s",
3576 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3577 vty_out (vty, "Record priority: %s%s",
3578 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003579 vty_out (vty, "Timestamp precision: %d%s",
3580 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003581
3582 return CMD_SUCCESS;
3583}
3584
paul718e3742002-12-13 20:15:29 +00003585DEFUN (config_log_stdout,
3586 config_log_stdout_cmd,
3587 "log stdout",
3588 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003589 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003590{
ajs274a4a42004-12-07 15:39:31 +00003591 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3592 return CMD_SUCCESS;
3593}
3594
3595DEFUN (config_log_stdout_level,
3596 config_log_stdout_level_cmd,
3597 "log stdout "LOG_LEVELS,
3598 "Logging control\n"
3599 "Set stdout logging level\n"
3600 LOG_LEVEL_DESC)
3601{
3602 int level;
3603
3604 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3605 return CMD_ERR_NO_MATCH;
3606 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003607 return CMD_SUCCESS;
3608}
3609
3610DEFUN (no_config_log_stdout,
3611 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003612 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003613 NO_STR
3614 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003615 "Cancel logging to stdout\n"
3616 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003617{
ajs274a4a42004-12-07 15:39:31 +00003618 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003619 return CMD_SUCCESS;
3620}
3621
ajs274a4a42004-12-07 15:39:31 +00003622DEFUN (config_log_monitor,
3623 config_log_monitor_cmd,
3624 "log monitor",
paul718e3742002-12-13 20:15:29 +00003625 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003626 "Set terminal line (monitor) logging level\n")
3627{
3628 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3629 return CMD_SUCCESS;
3630}
3631
3632DEFUN (config_log_monitor_level,
3633 config_log_monitor_level_cmd,
3634 "log monitor "LOG_LEVELS,
3635 "Logging control\n"
3636 "Set terminal line (monitor) logging level\n"
3637 LOG_LEVEL_DESC)
3638{
3639 int level;
3640
3641 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3642 return CMD_ERR_NO_MATCH;
3643 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3644 return CMD_SUCCESS;
3645}
3646
3647DEFUN (no_config_log_monitor,
3648 no_config_log_monitor_cmd,
3649 "no log monitor [LEVEL]",
3650 NO_STR
3651 "Logging control\n"
3652 "Disable terminal line (monitor) logging\n"
3653 "Logging level\n")
3654{
3655 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3656 return CMD_SUCCESS;
3657}
3658
3659static int
3660set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003661{
3662 int ret;
paul9035efa2004-10-10 11:56:56 +00003663 char *p = NULL;
3664 const char *fullpath;
3665
paul718e3742002-12-13 20:15:29 +00003666 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003667 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003668 {
paul9035efa2004-10-10 11:56:56 +00003669 char cwd[MAXPATHLEN+1];
3670 cwd[MAXPATHLEN] = '\0';
3671
3672 if (getcwd (cwd, MAXPATHLEN) == NULL)
3673 {
3674 zlog_err ("config_log_file: Unable to alloc mem!");
3675 return CMD_WARNING;
3676 }
3677
ajs274a4a42004-12-07 15:39:31 +00003678 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003679 == NULL)
3680 {
3681 zlog_err ("config_log_file: Unable to alloc mem!");
3682 return CMD_WARNING;
3683 }
ajs274a4a42004-12-07 15:39:31 +00003684 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003685 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003686 }
3687 else
ajs274a4a42004-12-07 15:39:31 +00003688 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003689
ajs274a4a42004-12-07 15:39:31 +00003690 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003691
paul9035efa2004-10-10 11:56:56 +00003692 if (p)
3693 XFREE (MTYPE_TMP, p);
3694
paul718e3742002-12-13 20:15:29 +00003695 if (!ret)
3696 {
ajs274a4a42004-12-07 15:39:31 +00003697 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003698 return CMD_WARNING;
3699 }
3700
3701 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003702 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003703
paul05865c92005-10-26 05:49:54 +00003704 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003705
3706 return CMD_SUCCESS;
3707}
3708
ajs274a4a42004-12-07 15:39:31 +00003709DEFUN (config_log_file,
3710 config_log_file_cmd,
3711 "log file FILENAME",
3712 "Logging control\n"
3713 "Logging to file\n"
3714 "Logging filename\n")
3715{
3716 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3717}
3718
3719DEFUN (config_log_file_level,
3720 config_log_file_level_cmd,
3721 "log file FILENAME "LOG_LEVELS,
3722 "Logging control\n"
3723 "Logging to file\n"
3724 "Logging filename\n"
3725 LOG_LEVEL_DESC)
3726{
3727 int level;
3728
3729 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3730 return CMD_ERR_NO_MATCH;
3731 return set_log_file(vty, argv[0], level);
3732}
3733
paul718e3742002-12-13 20:15:29 +00003734DEFUN (no_config_log_file,
3735 no_config_log_file_cmd,
3736 "no log file [FILENAME]",
3737 NO_STR
3738 "Logging control\n"
3739 "Cancel logging to file\n"
3740 "Logging file name\n")
3741{
3742 zlog_reset_file (NULL);
3743
3744 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003745 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003746
3747 host.logfile = NULL;
3748
3749 return CMD_SUCCESS;
3750}
3751
ajs274a4a42004-12-07 15:39:31 +00003752ALIAS (no_config_log_file,
3753 no_config_log_file_level_cmd,
3754 "no log file FILENAME LEVEL",
3755 NO_STR
3756 "Logging control\n"
3757 "Cancel logging to file\n"
3758 "Logging file name\n"
3759 "Logging level\n")
3760
paul718e3742002-12-13 20:15:29 +00003761DEFUN (config_log_syslog,
3762 config_log_syslog_cmd,
3763 "log syslog",
3764 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003765 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003766{
ajs274a4a42004-12-07 15:39:31 +00003767 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003768 return CMD_SUCCESS;
3769}
3770
ajs274a4a42004-12-07 15:39:31 +00003771DEFUN (config_log_syslog_level,
3772 config_log_syslog_level_cmd,
3773 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003774 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003775 "Set syslog logging level\n"
3776 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003777{
ajs274a4a42004-12-07 15:39:31 +00003778 int level;
paul12ab19f2003-07-26 06:14:55 +00003779
ajs274a4a42004-12-07 15:39:31 +00003780 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3781 return CMD_ERR_NO_MATCH;
3782 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3783 return CMD_SUCCESS;
3784}
paul12ab19f2003-07-26 06:14:55 +00003785
ajs274a4a42004-12-07 15:39:31 +00003786DEFUN_DEPRECATED (config_log_syslog_facility,
3787 config_log_syslog_facility_cmd,
3788 "log syslog facility "LOG_FACILITIES,
3789 "Logging control\n"
3790 "Logging goes to syslog\n"
3791 "(Deprecated) Facility parameter for syslog messages\n"
3792 LOG_FACILITY_DESC)
3793{
3794 int facility;
paul12ab19f2003-07-26 06:14:55 +00003795
ajs274a4a42004-12-07 15:39:31 +00003796 if ((facility = facility_match(argv[0])) < 0)
3797 return CMD_ERR_NO_MATCH;
3798
3799 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003800 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003801 return CMD_SUCCESS;
3802}
3803
3804DEFUN (no_config_log_syslog,
3805 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003806 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003807 NO_STR
3808 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003809 "Cancel logging to syslog\n"
3810 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003811{
ajs274a4a42004-12-07 15:39:31 +00003812 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003813 return CMD_SUCCESS;
3814}
3815
paul12ab19f2003-07-26 06:14:55 +00003816ALIAS (no_config_log_syslog,
3817 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003818 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003819 NO_STR
3820 "Logging control\n"
3821 "Logging goes to syslog\n"
3822 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003823 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003824
ajs274a4a42004-12-07 15:39:31 +00003825DEFUN (config_log_facility,
3826 config_log_facility_cmd,
3827 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003828 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003829 "Facility parameter for syslog messages\n"
3830 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003831{
ajs274a4a42004-12-07 15:39:31 +00003832 int facility;
3833
3834 if ((facility = facility_match(argv[0])) < 0)
3835 return CMD_ERR_NO_MATCH;
3836 zlog_default->facility = facility;
3837 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003838}
3839
ajs274a4a42004-12-07 15:39:31 +00003840DEFUN (no_config_log_facility,
3841 no_config_log_facility_cmd,
3842 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003843 NO_STR
3844 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003845 "Reset syslog facility to default (daemon)\n"
3846 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003847{
ajs274a4a42004-12-07 15:39:31 +00003848 zlog_default->facility = LOG_DAEMON;
3849 return CMD_SUCCESS;
3850}
3851
3852DEFUN_DEPRECATED (config_log_trap,
3853 config_log_trap_cmd,
3854 "log trap "LOG_LEVELS,
3855 "Logging control\n"
3856 "(Deprecated) Set logging level and default for all destinations\n"
3857 LOG_LEVEL_DESC)
3858{
3859 int new_level ;
3860 int i;
3861
3862 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3863 return CMD_ERR_NO_MATCH;
3864
3865 zlog_default->default_lvl = new_level;
3866 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3867 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3868 zlog_default->maxlvl[i] = new_level;
3869 return CMD_SUCCESS;
3870}
3871
3872DEFUN_DEPRECATED (no_config_log_trap,
3873 no_config_log_trap_cmd,
3874 "no log trap [LEVEL]",
3875 NO_STR
3876 "Logging control\n"
3877 "Permit all logging information\n"
3878 "Logging level\n")
3879{
3880 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003881 return CMD_SUCCESS;
3882}
3883
3884DEFUN (config_log_record_priority,
3885 config_log_record_priority_cmd,
3886 "log record-priority",
3887 "Logging control\n"
3888 "Log the priority of the message within the message\n")
3889{
3890 zlog_default->record_priority = 1 ;
3891 return CMD_SUCCESS;
3892}
3893
3894DEFUN (no_config_log_record_priority,
3895 no_config_log_record_priority_cmd,
3896 "no log record-priority",
3897 NO_STR
3898 "Logging control\n"
3899 "Do not log the priority of the message within the message\n")
3900{
3901 zlog_default->record_priority = 0 ;
3902 return CMD_SUCCESS;
3903}
3904
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003905DEFUN (config_log_timestamp_precision,
3906 config_log_timestamp_precision_cmd,
3907 "log timestamp precision <0-6>",
3908 "Logging control\n"
3909 "Timestamp configuration\n"
3910 "Set the timestamp precision\n"
3911 "Number of subsecond digits\n")
3912{
3913 if (argc != 1)
3914 {
3915 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3916 return CMD_WARNING;
3917 }
3918
3919 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3920 zlog_default->timestamp_precision, argv[0], 0, 6);
3921 return CMD_SUCCESS;
3922}
3923
3924DEFUN (no_config_log_timestamp_precision,
3925 no_config_log_timestamp_precision_cmd,
3926 "no log timestamp precision",
3927 NO_STR
3928 "Logging control\n"
3929 "Timestamp configuration\n"
3930 "Reset the timestamp precision to the default value of 0\n")
3931{
3932 zlog_default->timestamp_precision = 0 ;
3933 return CMD_SUCCESS;
3934}
3935
paul3b0c5d92005-03-08 10:43:43 +00003936DEFUN (banner_motd_file,
3937 banner_motd_file_cmd,
3938 "banner motd file [FILE]",
3939 "Set banner\n"
3940 "Banner for motd\n"
3941 "Banner from a file\n"
3942 "Filename\n")
3943{
paulb45da6f2005-03-08 15:16:57 +00003944 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003945 XFREE (MTYPE_HOST, host.motdfile);
3946 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003947
paul3b0c5d92005-03-08 10:43:43 +00003948 return CMD_SUCCESS;
3949}
paul718e3742002-12-13 20:15:29 +00003950
3951DEFUN (banner_motd_default,
3952 banner_motd_default_cmd,
3953 "banner motd default",
3954 "Set banner string\n"
3955 "Strings for motd\n"
3956 "Default string\n")
3957{
3958 host.motd = default_motd;
3959 return CMD_SUCCESS;
3960}
3961
3962DEFUN (no_banner_motd,
3963 no_banner_motd_cmd,
3964 "no banner motd",
3965 NO_STR
3966 "Set banner string\n"
3967 "Strings for motd\n")
3968{
3969 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003970 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003971 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003972 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003973 return CMD_SUCCESS;
3974}
3975
3976/* Set config filename. Called from vty.c */
3977void
3978host_config_set (char *filename)
3979{
Chris Caputo228da422009-07-18 05:44:03 +00003980 if (host.config)
3981 XFREE (MTYPE_HOST, host.config);
paul05865c92005-10-26 05:49:54 +00003982 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003983}
3984
3985void
3986install_default (enum node_type node)
3987{
3988 install_element (node, &config_exit_cmd);
3989 install_element (node, &config_quit_cmd);
3990 install_element (node, &config_end_cmd);
3991 install_element (node, &config_help_cmd);
3992 install_element (node, &config_list_cmd);
3993
3994 install_element (node, &config_write_terminal_cmd);
3995 install_element (node, &config_write_file_cmd);
3996 install_element (node, &config_write_memory_cmd);
3997 install_element (node, &config_write_cmd);
3998 install_element (node, &show_running_config_cmd);
3999}
4000
4001/* Initialize command interface. Install basic nodes and commands. */
4002void
4003cmd_init (int terminal)
4004{
Christian Frankecd40b322013-09-30 12:27:51 +00004005 command_cr = XSTRDUP(MTYPE_CMD_TOKENS, "<cr>");
4006 token_cr.type = TOKEN_TERMINAL;
4007 token_cr.cmd = command_cr;
4008 token_cr.desc = XSTRDUP(MTYPE_CMD_TOKENS, "");
Chris Caputo228da422009-07-18 05:44:03 +00004009
paul718e3742002-12-13 20:15:29 +00004010 /* Allocate initial top vector of commands. */
4011 cmdvec = vector_init (VECTOR_MIN_SIZE);
4012
4013 /* Default host value settings. */
4014 host.name = NULL;
4015 host.password = NULL;
4016 host.enable = NULL;
4017 host.logfile = NULL;
4018 host.config = NULL;
4019 host.lines = -1;
4020 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00004021 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00004022
4023 /* Install top nodes. */
4024 install_node (&view_node, NULL);
4025 install_node (&enable_node, NULL);
4026 install_node (&auth_node, NULL);
4027 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01004028 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00004029 install_node (&config_node, config_write_host);
4030
4031 /* Each node's basic commands. */
4032 install_element (VIEW_NODE, &show_version_cmd);
4033 if (terminal)
4034 {
4035 install_element (VIEW_NODE, &config_list_cmd);
4036 install_element (VIEW_NODE, &config_exit_cmd);
4037 install_element (VIEW_NODE, &config_quit_cmd);
4038 install_element (VIEW_NODE, &config_help_cmd);
4039 install_element (VIEW_NODE, &config_enable_cmd);
4040 install_element (VIEW_NODE, &config_terminal_length_cmd);
4041 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00004042 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00004043 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01004044
4045 install_element (RESTRICTED_NODE, &config_list_cmd);
4046 install_element (RESTRICTED_NODE, &config_exit_cmd);
4047 install_element (RESTRICTED_NODE, &config_quit_cmd);
4048 install_element (RESTRICTED_NODE, &config_help_cmd);
4049 install_element (RESTRICTED_NODE, &config_enable_cmd);
4050 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
4051 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
4052 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00004053 }
4054
4055 if (terminal)
4056 {
4057 install_default (ENABLE_NODE);
4058 install_element (ENABLE_NODE, &config_disable_cmd);
4059 install_element (ENABLE_NODE, &config_terminal_cmd);
4060 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
4061 }
4062 install_element (ENABLE_NODE, &show_startup_config_cmd);
4063 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00004064
4065 if (terminal)
paul718e3742002-12-13 20:15:29 +00004066 {
hassoe7168df2004-10-03 20:11:32 +00004067 install_element (ENABLE_NODE, &config_terminal_length_cmd);
4068 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00004069 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00004070 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00004071 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00004072
4073 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00004074 }
4075
4076 install_element (CONFIG_NODE, &hostname_cmd);
4077 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00004078
hassoea8e9d92004-10-07 21:32:14 +00004079 if (terminal)
4080 {
hassoe7168df2004-10-03 20:11:32 +00004081 install_element (CONFIG_NODE, &password_cmd);
4082 install_element (CONFIG_NODE, &password_text_cmd);
4083 install_element (CONFIG_NODE, &enable_password_cmd);
4084 install_element (CONFIG_NODE, &enable_password_text_cmd);
4085 install_element (CONFIG_NODE, &no_enable_password_cmd);
4086
paul718e3742002-12-13 20:15:29 +00004087 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00004088 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00004089 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00004090 install_element (CONFIG_NODE, &config_log_monitor_cmd);
4091 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
4092 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00004093 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00004094 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00004095 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00004096 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00004097 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00004098 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00004099 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00004100 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00004101 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00004102 install_element (CONFIG_NODE, &config_log_facility_cmd);
4103 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00004104 install_element (CONFIG_NODE, &config_log_trap_cmd);
4105 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
4106 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
4107 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00004108 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
4109 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00004110 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
4111 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
4112 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00004113 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00004114 install_element (CONFIG_NODE, &no_banner_motd_cmd);
4115 install_element (CONFIG_NODE, &service_terminal_length_cmd);
4116 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00004117
paul354d1192005-04-25 16:26:42 +00004118 install_element (VIEW_NODE, &show_thread_cpu_cmd);
4119 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01004120 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
Paul Jakmae276eb82010-01-09 16:15:00 +00004121
4122 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00004123 install_element (VIEW_NODE, &show_work_queues_cmd);
4124 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00004125 }
paul718e3742002-12-13 20:15:29 +00004126 srand(time(NULL));
4127}
Chris Caputo228da422009-07-18 05:44:03 +00004128
Christian Frankecd40b322013-09-30 12:27:51 +00004129static void
4130cmd_terminate_token(struct cmd_token *token)
4131{
4132 unsigned int i, j;
4133 vector keyword_vect;
4134
4135 if (token->multiple)
4136 {
4137 for (i = 0; i < vector_active(token->multiple); i++)
4138 cmd_terminate_token(vector_slot(token->multiple, i));
4139 vector_free(token->multiple);
4140 token->multiple = NULL;
4141 }
4142
4143 if (token->keyword)
4144 {
4145 for (i = 0; i < vector_active(token->keyword); i++)
4146 {
4147 keyword_vect = vector_slot(token->keyword, i);
4148 for (j = 0; j < vector_active(keyword_vect); j++)
4149 cmd_terminate_token(vector_slot(keyword_vect, j));
4150 vector_free(keyword_vect);
4151 }
4152 vector_free(token->keyword);
4153 token->keyword = NULL;
4154 }
4155
4156 XFREE(MTYPE_CMD_TOKENS, token->cmd);
4157 XFREE(MTYPE_CMD_TOKENS, token->desc);
4158
4159 XFREE(MTYPE_CMD_TOKENS, token);
4160}
4161
4162static void
4163cmd_terminate_element(struct cmd_element *cmd)
4164{
4165 unsigned int i;
4166
4167 if (cmd->tokens == NULL)
4168 return;
4169
4170 for (i = 0; i < vector_active(cmd->tokens); i++)
4171 cmd_terminate_token(vector_slot(cmd->tokens, i));
4172
4173 vector_free(cmd->tokens);
4174 cmd->tokens = NULL;
4175}
4176
Chris Caputo228da422009-07-18 05:44:03 +00004177void
4178cmd_terminate ()
4179{
Christian Frankecd40b322013-09-30 12:27:51 +00004180 unsigned int i, j;
Chris Caputo228da422009-07-18 05:44:03 +00004181 struct cmd_node *cmd_node;
4182 struct cmd_element *cmd_element;
Christian Frankecd40b322013-09-30 12:27:51 +00004183 vector cmd_node_v;
Chris Caputo228da422009-07-18 05:44:03 +00004184
4185 if (cmdvec)
4186 {
4187 for (i = 0; i < vector_active (cmdvec); i++)
4188 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
4189 {
4190 cmd_node_v = cmd_node->cmd_vector;
4191
4192 for (j = 0; j < vector_active (cmd_node_v); j++)
Christian Frankecd40b322013-09-30 12:27:51 +00004193 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL)
4194 cmd_terminate_element(cmd_element);
Chris Caputo228da422009-07-18 05:44:03 +00004195
4196 vector_free (cmd_node_v);
4197 }
4198
4199 vector_free (cmdvec);
4200 cmdvec = NULL;
4201 }
4202
4203 if (command_cr)
Christian Frankecd40b322013-09-30 12:27:51 +00004204 XFREE(MTYPE_CMD_TOKENS, command_cr);
4205 if (token_cr.desc)
4206 XFREE(MTYPE_CMD_TOKENS, token_cr.desc);
Chris Caputo228da422009-07-18 05:44:03 +00004207 if (host.name)
4208 XFREE (MTYPE_HOST, host.name);
4209 if (host.password)
4210 XFREE (MTYPE_HOST, host.password);
4211 if (host.password_encrypt)
4212 XFREE (MTYPE_HOST, host.password_encrypt);
4213 if (host.enable)
4214 XFREE (MTYPE_HOST, host.enable);
4215 if (host.enable_encrypt)
4216 XFREE (MTYPE_HOST, host.enable_encrypt);
4217 if (host.logfile)
4218 XFREE (MTYPE_HOST, host.logfile);
4219 if (host.motdfile)
4220 XFREE (MTYPE_HOST, host.motdfile);
4221 if (host.config)
4222 XFREE (MTYPE_HOST, host.config);
4223}