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