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