blob: f0ddb6d742b6d51558804b9fc0ccc48d25291eef [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Command interpreter routine for virtual terminal [aka TeletYpe]
2 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation; either version 2, or (at your
9option) any later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include <zebra.h>
22
23#include "command.h"
24#include "memory.h"
25#include "log.h"
26#include "version.h"
27
28/* Command vector which includes some level of command lists. Normally
29 each daemon maintains each own cmdvec. */
30vector cmdvec;
31
32/* Host information structure. */
33struct host host;
34
35/* Default motd string. */
36char *default_motd =
37"\r\n\
38Hello, this is zebra (version " ZEBRA_VERSION ").\r\n\
39Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
40\r\n";
41
42/* Standard command node structures. */
43struct cmd_node auth_node =
44{
45 AUTH_NODE,
46 "Password: ",
47};
48
49struct cmd_node view_node =
50{
51 VIEW_NODE,
52 "%s> ",
53};
54
55struct cmd_node auth_enable_node =
56{
57 AUTH_ENABLE_NODE,
58 "Password: ",
59};
60
61struct cmd_node enable_node =
62{
63 ENABLE_NODE,
64 "%s# ",
65};
66
67struct cmd_node config_node =
68{
69 CONFIG_NODE,
70 "%s(config)# ",
71 1
72};
73
74/* Utility function to concatenate argv argument into a single string
75 with inserting ' ' character between each argument. */
76char *
77argv_concat (char **argv, int argc, int shift)
78{
79 int i;
80 int len;
81 int index;
82 char *str;
83
84 str = NULL;
85 index = 0;
86
87 for (i = shift; i < argc; i++)
88 {
89 len = strlen (argv[i]);
90
91 if (i == shift)
92 {
93 str = XSTRDUP (MTYPE_TMP, argv[i]);
94 index = len;
95 }
96 else
97 {
98 str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
99 str[index++] = ' ';
100 memcpy (str + index, argv[i], len);
101 index += len;
102 str[index] = '\0';
103 }
104 }
105 return str;
106}
107
108/* Install top node of command vector. */
109void
110install_node (struct cmd_node *node,
111 int (*func) (struct vty *))
112{
113 vector_set_index (cmdvec, node->node, node);
114 node->func = func;
115 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
116}
117
118/* Compare two command's string. Used in sort_node (). */
119int
120cmp_node (const void *p, const void *q)
121{
122 struct cmd_element *a = *(struct cmd_element **)p;
123 struct cmd_element *b = *(struct cmd_element **)q;
124
125 return strcmp (a->string, b->string);
126}
127
128int
129cmp_desc (const void *p, const void *q)
130{
131 struct desc *a = *(struct desc **)p;
132 struct desc *b = *(struct desc **)q;
133
134 return strcmp (a->cmd, b->cmd);
135}
136
137/* Sort each node's command element according to command string. */
138void
139sort_node ()
140{
141 int i, j;
142 struct cmd_node *cnode;
143 vector descvec;
144 struct cmd_element *cmd_element;
145
146 for (i = 0; i < vector_max (cmdvec); i++)
147 if ((cnode = vector_slot (cmdvec, i)) != NULL)
148 {
149 vector cmd_vector = cnode->cmd_vector;
150 qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
151
152 for (j = 0; j < vector_max (cmd_vector); j++)
153 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
154 {
155 descvec = vector_slot (cmd_element->strvec,
156 vector_max (cmd_element->strvec) - 1);
157 qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
158 }
159 }
160}
161
162/* Breaking up string into each command piece. I assume given
163 character is separated by a space character. Return value is a
164 vector which includes char ** data element. */
165vector
166cmd_make_strvec (char *string)
167{
168 char *cp, *start, *token;
169 int strlen;
170 vector strvec;
171
172 if (string == NULL)
173 return NULL;
174
175 cp = string;
176
177 /* Skip white spaces. */
178 while (isspace ((int) *cp) && *cp != '\0')
179 cp++;
180
181 /* Return if there is only white spaces */
182 if (*cp == '\0')
183 return NULL;
184
185 if (*cp == '!' || *cp == '#')
186 return NULL;
187
188 /* Prepare return vector. */
189 strvec = vector_init (VECTOR_MIN_SIZE);
190
191 /* Copy each command piece and set into vector. */
192 while (1)
193 {
194 start = cp;
195 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
196 *cp != '\0')
197 cp++;
198 strlen = cp - start;
199 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
200 memcpy (token, start, strlen);
201 *(token + strlen) = '\0';
202 vector_set (strvec, token);
203
204 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
205 *cp != '\0')
206 cp++;
207
208 if (*cp == '\0')
209 return strvec;
210 }
211}
212
213/* Free allocated string vector. */
214void
215cmd_free_strvec (vector v)
216{
217 int i;
218 char *cp;
219
220 if (!v)
221 return;
222
223 for (i = 0; i < vector_max (v); i++)
224 if ((cp = vector_slot (v, i)) != NULL)
225 XFREE (MTYPE_STRVEC, cp);
226
227 vector_free (v);
228}
229
230/* Fetch next description. Used in cmd_make_descvec(). */
231char *
232cmd_desc_str (char **string)
233{
234 char *cp, *start, *token;
235 int strlen;
236
237 cp = *string;
238
239 if (cp == NULL)
240 return NULL;
241
242 /* Skip white spaces. */
243 while (isspace ((int) *cp) && *cp != '\0')
244 cp++;
245
246 /* Return if there is only white spaces */
247 if (*cp == '\0')
248 return NULL;
249
250 start = cp;
251
252 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
253 cp++;
254
255 strlen = cp - start;
256 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
257 memcpy (token, start, strlen);
258 *(token + strlen) = '\0';
259
260 *string = cp;
261
262 return token;
263}
264
265/* New string vector. */
266vector
267cmd_make_descvec (char *string, char *descstr)
268{
269 int multiple = 0;
270 char *sp;
271 char *token;
272 int len;
273 char *cp;
274 char *dp;
275 vector allvec;
276 vector strvec = NULL;
277 struct desc *desc;
278
279 cp = string;
280 dp = descstr;
281
282 if (cp == NULL)
283 return NULL;
284
285 allvec = vector_init (VECTOR_MIN_SIZE);
286
287 while (1)
288 {
289 while (isspace ((int) *cp) && *cp != '\0')
290 cp++;
291
292 if (*cp == '(')
293 {
294 multiple = 1;
295 cp++;
296 }
297 if (*cp == ')')
298 {
299 multiple = 0;
300 cp++;
301 }
302 if (*cp == '|')
303 {
304 if (! multiple)
305 {
306 fprintf (stderr, "Command parse error!: %s\n", string);
307 exit (1);
308 }
309 cp++;
310 }
311
312 while (isspace ((int) *cp) && *cp != '\0')
313 cp++;
314
315 if (*cp == '(')
316 {
317 multiple = 1;
318 cp++;
319 }
320
321 if (*cp == '\0')
322 return allvec;
323
324 sp = cp;
325
326 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
327 cp++;
328
329 len = cp - sp;
330
331 token = XMALLOC (MTYPE_STRVEC, len + 1);
332 memcpy (token, sp, len);
333 *(token + len) = '\0';
334
335 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
336 desc->cmd = token;
337 desc->str = cmd_desc_str (&dp);
338
339 if (multiple)
340 {
341 if (multiple == 1)
342 {
343 strvec = vector_init (VECTOR_MIN_SIZE);
344 vector_set (allvec, strvec);
345 }
346 multiple++;
347 }
348 else
349 {
350 strvec = vector_init (VECTOR_MIN_SIZE);
351 vector_set (allvec, strvec);
352 }
353 vector_set (strvec, desc);
354 }
355}
356
357/* Count mandantory string vector size. This is to determine inputed
358 command has enough command length. */
359int
360cmd_cmdsize (vector strvec)
361{
362 int i;
363 char *str;
364 int size = 0;
365 vector descvec;
366
367 for (i = 0; i < vector_max (strvec); i++)
368 {
369 descvec = vector_slot (strvec, i);
370
371 if (vector_max (descvec) == 1)
372 {
373 struct desc *desc = vector_slot (descvec, 0);
374
375 str = desc->cmd;
376
377 if (str == NULL || CMD_OPTION (str))
378 return size;
379 else
380 size++;
381 }
382 else
383 size++;
384 }
385 return size;
386}
387
388/* Return prompt character of specified node. */
389char *
390cmd_prompt (enum node_type node)
391{
392 struct cmd_node *cnode;
393
394 cnode = vector_slot (cmdvec, node);
395 return cnode->prompt;
396}
397
398/* Install a command into a node. */
399void
400install_element (enum node_type ntype, struct cmd_element *cmd)
401{
402 struct cmd_node *cnode;
403
404 cnode = vector_slot (cmdvec, ntype);
405
406 if (cnode == NULL)
407 {
408 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
409 ntype);
410 exit (1);
411 }
412
413 vector_set (cnode->cmd_vector, cmd);
414
415 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
416 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
417}
418
419static unsigned char itoa64[] =
420"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
421
422void
423to64(char *s, long v, int n)
424{
425 while (--n >= 0)
426 {
427 *s++ = itoa64[v&0x3f];
428 v >>= 6;
429 }
430}
431
432char *zencrypt (char *passwd)
433{
434 char salt[6];
435 struct timeval tv;
436 char *crypt (const char *, const char *);
437
438 gettimeofday(&tv,0);
439
440 to64(&salt[0], random(), 3);
441 to64(&salt[3], tv.tv_usec, 3);
442 salt[5] = '\0';
443
444 return crypt (passwd, salt);
445}
446
447/* This function write configuration of this host. */
448int
449config_write_host (struct vty *vty)
450{
451 if (host.name)
452 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
453
454 if (host.encrypt)
455 {
456 if (host.password_encrypt)
457 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
458 if (host.enable_encrypt)
459 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
460 }
461 else
462 {
463 if (host.password)
464 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
465 if (host.enable)
466 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
467 }
468
469 if (host.logfile)
470 vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
471
472 if (host.log_stdout)
473 vty_out (vty, "log stdout%s", VTY_NEWLINE);
474
475 if (host.log_syslog)
476 vty_out (vty, "log syslog%s", VTY_NEWLINE);
477
478 if (zlog_default->maskpri != LOG_DEBUG)
479 vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
480
481 if (zlog_default->record_priority == 1)
482 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
483
484 if (host.advanced)
485 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
486
487 if (host.encrypt)
488 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
489
490 if (host.lines >= 0)
491 vty_out (vty, "service terminal-length %d%s", host.lines,
492 VTY_NEWLINE);
493
494 if (! host.motd)
495 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
496
497 return 1;
498}
499
500/* Utility function for getting command vector. */
501vector
502cmd_node_vector (vector v, enum node_type ntype)
503{
504 struct cmd_node *cnode = vector_slot (v, ntype);
505 return cnode->cmd_vector;
506}
507
508/* Filter command vector by symbol */
509int
510cmd_filter_by_symbol (char *command, char *symbol)
511{
512 int i, lim;
513
514 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
515 {
516 i = 0;
517 lim = strlen (command);
518 while (i < lim)
519 {
520 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
521 return 1;
522 i++;
523 }
524 return 0;
525 }
526 if (strcmp (symbol, "STRING") == 0)
527 {
528 i = 0;
529 lim = strlen (command);
530 while (i < lim)
531 {
532 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
533 return 1;
534 i++;
535 }
536 return 0;
537 }
538 if (strcmp (symbol, "IFNAME") == 0)
539 {
540 i = 0;
541 lim = strlen (command);
542 while (i < lim)
543 {
544 if (! isalnum ((int) command[i]))
545 return 1;
546 i++;
547 }
548 return 0;
549 }
550 return 0;
551}
552
553/* Completion match types. */
554enum match_type
555{
556 no_match,
557 extend_match,
558 ipv4_prefix_match,
559 ipv4_match,
560 ipv6_prefix_match,
561 ipv6_match,
562 range_match,
563 vararg_match,
564 partly_match,
565 exact_match
566};
567
568enum match_type
569cmd_ipv4_match (char *str)
570{
571 char *sp;
572 int dots = 0, nums = 0;
573 char buf[4];
574
575 if (str == NULL)
576 return partly_match;
577
578 for (;;)
579 {
580 memset (buf, 0, sizeof (buf));
581 sp = str;
582 while (*str != '\0')
583 {
584 if (*str == '.')
585 {
586 if (dots >= 3)
587 return no_match;
588
589 if (*(str + 1) == '.')
590 return no_match;
591
592 if (*(str + 1) == '\0')
593 return partly_match;
594
595 dots++;
596 break;
597 }
598 if (!isdigit ((int) *str))
599 return no_match;
600
601 str++;
602 }
603
604 if (str - sp > 3)
605 return no_match;
606
607 strncpy (buf, sp, str - sp);
608 if (atoi (buf) > 255)
609 return no_match;
610
611 nums++;
612
613 if (*str == '\0')
614 break;
615
616 str++;
617 }
618
619 if (nums < 4)
620 return partly_match;
621
622 return exact_match;
623}
624
625enum match_type
626cmd_ipv4_prefix_match (char *str)
627{
628 char *sp;
629 int dots = 0;
630 char buf[4];
631
632 if (str == NULL)
633 return partly_match;
634
635 for (;;)
636 {
637 memset (buf, 0, sizeof (buf));
638 sp = str;
639 while (*str != '\0' && *str != '/')
640 {
641 if (*str == '.')
642 {
643 if (dots == 3)
644 return no_match;
645
646 if (*(str + 1) == '.' || *(str + 1) == '/')
647 return no_match;
648
649 if (*(str + 1) == '\0')
650 return partly_match;
651
652 dots++;
653 break;
654 }
655
656 if (!isdigit ((int) *str))
657 return no_match;
658
659 str++;
660 }
661
662 if (str - sp > 3)
663 return no_match;
664
665 strncpy (buf, sp, str - sp);
666 if (atoi (buf) > 255)
667 return no_match;
668
669 if (dots == 3)
670 {
671 if (*str == '/')
672 {
673 if (*(str + 1) == '\0')
674 return partly_match;
675
676 str++;
677 break;
678 }
679 else if (*str == '\0')
680 return partly_match;
681 }
682
683 if (*str == '\0')
684 return partly_match;
685
686 str++;
687 }
688
689 sp = str;
690 while (*str != '\0')
691 {
692 if (!isdigit ((int) *str))
693 return no_match;
694
695 str++;
696 }
697
698 if (atoi (sp) > 32)
699 return no_match;
700
701 return exact_match;
702}
703
704#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
705#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
706#define STATE_START 1
707#define STATE_COLON 2
708#define STATE_DOUBLE 3
709#define STATE_ADDR 4
710#define STATE_DOT 5
711#define STATE_SLASH 6
712#define STATE_MASK 7
713
714enum match_type
715cmd_ipv6_match (char *str)
716{
717 int state = STATE_START;
718 int colons = 0, nums = 0, double_colon = 0;
719 char *sp = NULL;
720
721 if (str == NULL)
722 return partly_match;
723
724 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
725 return no_match;
726
727 while (*str != '\0')
728 {
729 switch (state)
730 {
731 case STATE_START:
732 if (*str == ':')
733 {
734 if (*(str + 1) != ':' && *(str + 1) != '\0')
735 return no_match;
736 colons--;
737 state = STATE_COLON;
738 }
739 else
740 {
741 sp = str;
742 state = STATE_ADDR;
743 }
744
745 continue;
746 case STATE_COLON:
747 colons++;
748 if (*(str + 1) == ':')
749 state = STATE_DOUBLE;
750 else
751 {
752 sp = str + 1;
753 state = STATE_ADDR;
754 }
755 break;
756 case STATE_DOUBLE:
757 if (double_colon)
758 return no_match;
759
760 if (*(str + 1) == ':')
761 return no_match;
762 else
763 {
764 if (*(str + 1) != '\0')
765 colons++;
766 sp = str + 1;
767 state = STATE_ADDR;
768 }
769
770 double_colon++;
771 nums++;
772 break;
773 case STATE_ADDR:
774 if (*(str + 1) == ':' || *(str + 1) == '\0')
775 {
776 if (str - sp > 3)
777 return no_match;
778
779 nums++;
780 state = STATE_COLON;
781 }
782 if (*(str + 1) == '.')
783 state = STATE_DOT;
784 break;
785 case STATE_DOT:
786 state = STATE_ADDR;
787 break;
788 default:
789 break;
790 }
791
792 if (nums > 8)
793 return no_match;
794
795 if (colons > 7)
796 return no_match;
797
798 str++;
799 }
800
801#if 0
802 if (nums < 11)
803 return partly_match;
804#endif /* 0 */
805
806 return exact_match;
807}
808
809enum match_type
810cmd_ipv6_prefix_match (char *str)
811{
812 int state = STATE_START;
813 int colons = 0, nums = 0, double_colon = 0;
814 int mask;
815 char *sp = NULL;
816 char *endptr = NULL;
817
818 if (str == NULL)
819 return partly_match;
820
821 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
822 return no_match;
823
824 while (*str != '\0' && state != STATE_MASK)
825 {
826 switch (state)
827 {
828 case STATE_START:
829 if (*str == ':')
830 {
831 if (*(str + 1) != ':' && *(str + 1) != '\0')
832 return no_match;
833 colons--;
834 state = STATE_COLON;
835 }
836 else
837 {
838 sp = str;
839 state = STATE_ADDR;
840 }
841
842 continue;
843 case STATE_COLON:
844 colons++;
845 if (*(str + 1) == '/')
846 return no_match;
847 else if (*(str + 1) == ':')
848 state = STATE_DOUBLE;
849 else
850 {
851 sp = str + 1;
852 state = STATE_ADDR;
853 }
854 break;
855 case STATE_DOUBLE:
856 if (double_colon)
857 return no_match;
858
859 if (*(str + 1) == ':')
860 return no_match;
861 else
862 {
863 if (*(str + 1) != '\0' && *(str + 1) != '/')
864 colons++;
865 sp = str + 1;
866
867 if (*(str + 1) == '/')
868 state = STATE_SLASH;
869 else
870 state = STATE_ADDR;
871 }
872
873 double_colon++;
874 nums += 1;
875 break;
876 case STATE_ADDR:
877 if (*(str + 1) == ':' || *(str + 1) == '.'
878 || *(str + 1) == '\0' || *(str + 1) == '/')
879 {
880 if (str - sp > 3)
881 return no_match;
882
883 for (; sp <= str; sp++)
884 if (*sp == '/')
885 return no_match;
886
887 nums++;
888
889 if (*(str + 1) == ':')
890 state = STATE_COLON;
891 else if (*(str + 1) == '.')
892 state = STATE_DOT;
893 else if (*(str + 1) == '/')
894 state = STATE_SLASH;
895 }
896 break;
897 case STATE_DOT:
898 state = STATE_ADDR;
899 break;
900 case STATE_SLASH:
901 if (*(str + 1) == '\0')
902 return partly_match;
903
904 state = STATE_MASK;
905 break;
906 default:
907 break;
908 }
909
910 if (nums > 11)
911 return no_match;
912
913 if (colons > 7)
914 return no_match;
915
916 str++;
917 }
918
919 if (state < STATE_MASK)
920 return partly_match;
921
922 mask = strtol (str, &endptr, 10);
923 if (*endptr != '\0')
924 return no_match;
925
926 if (mask < 0 || mask > 128)
927 return no_match;
928
929/* I don't know why mask < 13 makes command match partly.
930 Forgive me to make this comments. I Want to set static default route
931 because of lack of function to originate default in ospf6d; sorry
932 yasu
933 if (mask < 13)
934 return partly_match;
935*/
936
937 return exact_match;
938}
939
940#define DECIMAL_STRLEN_MAX 10
941
942int
943cmd_range_match (char *range, char *str)
944{
945 char *p;
946 char buf[DECIMAL_STRLEN_MAX + 1];
947 char *endptr = NULL;
948 unsigned long min, max, val;
949
950 if (str == NULL)
951 return 1;
952
953 val = strtoul (str, &endptr, 10);
954 if (*endptr != '\0')
955 return 0;
956
957 range++;
958 p = strchr (range, '-');
959 if (p == NULL)
960 return 0;
961 if (p - range > DECIMAL_STRLEN_MAX)
962 return 0;
963 strncpy (buf, range, p - range);
964 buf[p - range] = '\0';
965 min = strtoul (buf, &endptr, 10);
966 if (*endptr != '\0')
967 return 0;
968
969 range = p + 1;
970 p = strchr (range, '>');
971 if (p == NULL)
972 return 0;
973 if (p - range > DECIMAL_STRLEN_MAX)
974 return 0;
975 strncpy (buf, range, p - range);
976 buf[p - range] = '\0';
977 max = strtoul (buf, &endptr, 10);
978 if (*endptr != '\0')
979 return 0;
980
981 if (val < min || val > max)
982 return 0;
983
984 return 1;
985}
986
987/* Make completion match and return match type flag. */
988enum match_type
989cmd_filter_by_completion (char *command, vector v, int index)
990{
991 int i;
992 char *str;
993 struct cmd_element *cmd_element;
994 enum match_type match_type;
995 vector descvec;
996 struct desc *desc;
997
998 match_type = no_match;
999
1000 /* If command and cmd_element string does not match set NULL to vector */
1001 for (i = 0; i < vector_max (v); i++)
1002 if ((cmd_element = vector_slot (v, i)) != NULL)
1003 {
1004 if (index >= vector_max (cmd_element->strvec))
1005 vector_slot (v, i) = NULL;
1006 else
1007 {
1008 int j;
1009 int matched = 0;
1010
1011 descvec = vector_slot (cmd_element->strvec, index);
1012
1013 for (j = 0; j < vector_max (descvec); j++)
1014 {
1015 desc = vector_slot (descvec, j);
1016 str = desc->cmd;
1017
1018 if (CMD_VARARG (str))
1019 {
1020 if (match_type < vararg_match)
1021 match_type = vararg_match;
1022 matched++;
1023 }
1024 else if (CMD_RANGE (str))
1025 {
1026 if (cmd_range_match (str, command))
1027 {
1028 if (match_type < range_match)
1029 match_type = range_match;
1030
1031 matched++;
1032 }
1033 }
1034 else if (CMD_IPV6 (str))
1035 {
1036 if (cmd_ipv6_match (command))
1037 {
1038 if (match_type < ipv6_match)
1039 match_type = ipv6_match;
1040
1041 matched++;
1042 }
1043 }
1044 else if (CMD_IPV6_PREFIX (str))
1045 {
1046 if (cmd_ipv6_prefix_match (command))
1047 {
1048 if (match_type < ipv6_prefix_match)
1049 match_type = ipv6_prefix_match;
1050
1051 matched++;
1052 }
1053 }
1054 else if (CMD_IPV4 (str))
1055 {
1056 if (cmd_ipv4_match (command))
1057 {
1058 if (match_type < ipv4_match)
1059 match_type = ipv4_match;
1060
1061 matched++;
1062 }
1063 }
1064 else if (CMD_IPV4_PREFIX (str))
1065 {
1066 if (cmd_ipv4_prefix_match (command))
1067 {
1068 if (match_type < ipv4_prefix_match)
1069 match_type = ipv4_prefix_match;
1070 matched++;
1071 }
1072 }
1073 else
1074 /* Check is this point's argument optional ? */
1075 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1076 {
1077 if (match_type < extend_match)
1078 match_type = extend_match;
1079 matched++;
1080 }
1081 else if (strncmp (command, str, strlen (command)) == 0)
1082 {
1083 if (strcmp (command, str) == 0)
1084 match_type = exact_match;
1085 else
1086 {
1087 if (match_type < partly_match)
1088 match_type = partly_match;
1089 }
1090 matched++;
1091 }
1092 }
1093 if (! matched)
1094 vector_slot (v, i) = NULL;
1095 }
1096 }
1097 return match_type;
1098}
1099
1100/* Filter vector by command character with index. */
1101enum match_type
1102cmd_filter_by_string (char *command, vector v, int index)
1103{
1104 int i;
1105 char *str;
1106 struct cmd_element *cmd_element;
1107 enum match_type match_type;
1108 vector descvec;
1109 struct desc *desc;
1110
1111 match_type = no_match;
1112
1113 /* If command and cmd_element string does not match set NULL to vector */
1114 for (i = 0; i < vector_max (v); i++)
1115 if ((cmd_element = vector_slot (v, i)) != NULL)
1116 {
1117 /* If given index is bigger than max string vector of command,
1118 set NULL*/
1119 if (index >= vector_max (cmd_element->strvec))
1120 vector_slot (v, i) = NULL;
1121 else
1122 {
1123 int j;
1124 int matched = 0;
1125
1126 descvec = vector_slot (cmd_element->strvec, index);
1127
1128 for (j = 0; j < vector_max (descvec); j++)
1129 {
1130 desc = vector_slot (descvec, j);
1131 str = desc->cmd;
1132
1133 if (CMD_VARARG (str))
1134 {
1135 if (match_type < vararg_match)
1136 match_type = vararg_match;
1137 matched++;
1138 }
1139 else if (CMD_RANGE (str))
1140 {
1141 if (cmd_range_match (str, command))
1142 {
1143 if (match_type < range_match)
1144 match_type = range_match;
1145 matched++;
1146 }
1147 }
1148 else if (CMD_IPV6 (str))
1149 {
1150 if (cmd_ipv6_match (command) == exact_match)
1151 {
1152 if (match_type < ipv6_match)
1153 match_type = ipv6_match;
1154 matched++;
1155 }
1156 }
1157 else if (CMD_IPV6_PREFIX (str))
1158 {
1159 if (cmd_ipv6_prefix_match (command) == exact_match)
1160 {
1161 if (match_type < ipv6_prefix_match)
1162 match_type = ipv6_prefix_match;
1163 matched++;
1164 }
1165 }
1166 else if (CMD_IPV4 (str))
1167 {
1168 if (cmd_ipv4_match (command) == exact_match)
1169 {
1170 if (match_type < ipv4_match)
1171 match_type = ipv4_match;
1172 matched++;
1173 }
1174 }
1175 else if (CMD_IPV4_PREFIX (str))
1176 {
1177 if (cmd_ipv4_prefix_match (command) == exact_match)
1178 {
1179 if (match_type < ipv4_prefix_match)
1180 match_type = ipv4_prefix_match;
1181 matched++;
1182 }
1183 }
1184 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1185 {
1186 if (match_type < extend_match)
1187 match_type = extend_match;
1188 matched++;
1189 }
1190 else
1191 {
1192 if (strcmp (command, str) == 0)
1193 {
1194 match_type = exact_match;
1195 matched++;
1196 }
1197 }
1198 }
1199 if (! matched)
1200 vector_slot (v, i) = NULL;
1201 }
1202 }
1203 return match_type;
1204}
1205
1206/* Check ambiguous match */
1207int
1208is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1209{
1210 int i;
1211 int j;
1212 char *str = NULL;
1213 struct cmd_element *cmd_element;
1214 char *matched = NULL;
1215 vector descvec;
1216 struct desc *desc;
1217
1218 for (i = 0; i < vector_max (v); i++)
1219 if ((cmd_element = vector_slot (v, i)) != NULL)
1220 {
1221 int match = 0;
1222
1223 descvec = vector_slot (cmd_element->strvec, index);
1224
1225 for (j = 0; j < vector_max (descvec); j++)
1226 {
1227 enum match_type ret;
1228
1229 desc = vector_slot (descvec, j);
1230 str = desc->cmd;
1231
1232 switch (type)
1233 {
1234 case exact_match:
1235 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1236 && strcmp (command, str) == 0)
1237 match++;
1238 break;
1239 case partly_match:
1240 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1241 && strncmp (command, str, strlen (command)) == 0)
1242 {
1243 if (matched && strcmp (matched, str) != 0)
1244 return 1; /* There is ambiguous match. */
1245 else
1246 matched = str;
1247 match++;
1248 }
1249 break;
1250 case range_match:
1251 if (cmd_range_match (str, command))
1252 {
1253 if (matched && strcmp (matched, str) != 0)
1254 return 1;
1255 else
1256 matched = str;
1257 match++;
1258 }
1259 break;
1260 case ipv6_match:
1261 if (CMD_IPV6 (str))
1262 match++;
1263 break;
1264 case ipv6_prefix_match:
1265 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1266 {
1267 if (ret == partly_match)
1268 return 2; /* There is incomplete match. */
1269
1270 match++;
1271 }
1272 break;
1273 case ipv4_match:
1274 if (CMD_IPV4 (str))
1275 match++;
1276 break;
1277 case ipv4_prefix_match:
1278 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1279 {
1280 if (ret == partly_match)
1281 return 2; /* There is incomplete match. */
1282
1283 match++;
1284 }
1285 break;
1286 case extend_match:
1287 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1288 match++;
1289 break;
1290 case no_match:
1291 default:
1292 break;
1293 }
1294 }
1295 if (! match)
1296 vector_slot (v, i) = NULL;
1297 }
1298 return 0;
1299}
1300
1301/* If src matches dst return dst string, otherwise return NULL */
1302char *
1303cmd_entry_function (char *src, char *dst)
1304{
1305 /* Skip variable arguments. */
1306 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1307 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1308 return NULL;
1309
1310 /* In case of 'command \t', given src is NULL string. */
1311 if (src == NULL)
1312 return dst;
1313
1314 /* Matched with input string. */
1315 if (strncmp (src, dst, strlen (src)) == 0)
1316 return dst;
1317
1318 return NULL;
1319}
1320
1321/* If src matches dst return dst string, otherwise return NULL */
1322/* This version will return the dst string always if it is
1323 CMD_VARIABLE for '?' key processing */
1324char *
1325cmd_entry_function_desc (char *src, char *dst)
1326{
1327 if (CMD_VARARG (dst))
1328 return dst;
1329
1330 if (CMD_RANGE (dst))
1331 {
1332 if (cmd_range_match (dst, src))
1333 return dst;
1334 else
1335 return NULL;
1336 }
1337
1338 if (CMD_IPV6 (dst))
1339 {
1340 if (cmd_ipv6_match (src))
1341 return dst;
1342 else
1343 return NULL;
1344 }
1345
1346 if (CMD_IPV6_PREFIX (dst))
1347 {
1348 if (cmd_ipv6_prefix_match (src))
1349 return dst;
1350 else
1351 return NULL;
1352 }
1353
1354 if (CMD_IPV4 (dst))
1355 {
1356 if (cmd_ipv4_match (src))
1357 return dst;
1358 else
1359 return NULL;
1360 }
1361
1362 if (CMD_IPV4_PREFIX (dst))
1363 {
1364 if (cmd_ipv4_prefix_match (src))
1365 return dst;
1366 else
1367 return NULL;
1368 }
1369
1370 /* Optional or variable commands always match on '?' */
1371 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1372 return dst;
1373
1374 /* In case of 'command \t', given src is NULL string. */
1375 if (src == NULL)
1376 return dst;
1377
1378 if (strncmp (src, dst, strlen (src)) == 0)
1379 return dst;
1380 else
1381 return NULL;
1382}
1383
1384/* Check same string element existence. If it isn't there return
1385 1. */
1386int
1387cmd_unique_string (vector v, char *str)
1388{
1389 int i;
1390 char *match;
1391
1392 for (i = 0; i < vector_max (v); i++)
1393 if ((match = vector_slot (v, i)) != NULL)
1394 if (strcmp (match, str) == 0)
1395 return 0;
1396 return 1;
1397}
1398
1399/* Compare string to description vector. If there is same string
1400 return 1 else return 0. */
1401int
1402desc_unique_string (vector v, char *str)
1403{
1404 int i;
1405 struct desc *desc;
1406
1407 for (i = 0; i < vector_max (v); i++)
1408 if ((desc = vector_slot (v, i)) != NULL)
1409 if (strcmp (desc->cmd, str) == 0)
1410 return 1;
1411 return 0;
1412}
1413
paulb92938a2002-12-13 21:20:42 +00001414int
1415cmd_try_do_shortcut (enum node_type node, char* first_word) {
1416 if ( first_word != NULL &&
1417 node != AUTH_NODE &&
1418 node != VIEW_NODE &&
1419 node != AUTH_ENABLE_NODE &&
1420 node != ENABLE_NODE &&
1421 0 == strcmp( "do", first_word ) )
1422 return 1;
1423 return 0;
1424}
1425
paul718e3742002-12-13 20:15:29 +00001426/* '?' describe command support. */
1427vector
paulb92938a2002-12-13 21:20:42 +00001428cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001429{
1430 int i;
1431 vector cmd_vector;
1432#define INIT_MATCHVEC_SIZE 10
1433 vector matchvec;
1434 struct cmd_element *cmd_element;
1435 int index;
1436 static struct desc desc_cr = { "<cr>", "" };
1437
1438 /* Set index. */
1439 index = vector_max (vline) - 1;
1440
1441 /* Make copy vector of current node's command vector. */
1442 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1443
1444 /* Prepare match vector */
1445 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1446
1447 /* Filter commands. */
1448 for (i = 0; i < index; i++)
1449 {
1450 enum match_type match;
1451 char *command;
1452 int ret;
1453
1454 command = vector_slot (vline, i);
1455
1456 match = cmd_filter_by_completion (command, cmd_vector, i);
1457
1458 if (match == vararg_match)
1459 {
1460 struct cmd_element *cmd_element;
1461 vector descvec;
1462 int j, k;
1463
1464 for (j = 0; j < vector_max (cmd_vector); j++)
1465 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1466 {
1467 descvec = vector_slot (cmd_element->strvec,
1468 vector_max (cmd_element->strvec) - 1);
1469 for (k = 0; k < vector_max (descvec); k++)
1470 {
1471 struct desc *desc = vector_slot (descvec, k);
1472 vector_set (matchvec, desc);
1473 }
1474 }
1475
1476 vector_set (matchvec, &desc_cr);
1477
1478 vector_free (cmd_vector);
1479
1480 return matchvec;
1481 }
1482
1483 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1484 {
1485 vector_free (cmd_vector);
1486 *status = CMD_ERR_AMBIGUOUS;
1487 return NULL;
1488 }
1489 else if (ret == 2)
1490 {
1491 vector_free (cmd_vector);
1492 *status = CMD_ERR_NO_MATCH;
1493 return NULL;
1494 }
1495 }
1496
1497 /* Prepare match vector */
1498 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1499
1500 /* Make description vector. */
1501 for (i = 0; i < vector_max (cmd_vector); i++)
1502 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1503 {
1504 char *string = NULL;
1505 vector strvec = cmd_element->strvec;
1506
1507 if (index > vector_max (strvec))
1508 vector_slot (cmd_vector, i) = NULL;
1509 else
1510 {
1511 /* Check is command is completed. */
1512 if (index == vector_max (strvec))
1513 {
1514 string = "<cr>";
1515 if (! desc_unique_string (matchvec, string))
1516 vector_set (matchvec, &desc_cr);
1517 }
1518 else
1519 {
1520 int j;
1521 vector descvec = vector_slot (strvec, index);
1522 struct desc *desc;
1523
1524 for (j = 0; j < vector_max (descvec); j++)
1525 {
1526 desc = vector_slot (descvec, j);
1527 string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
1528 if (string)
1529 {
1530 /* Uniqueness check */
1531 if (! desc_unique_string (matchvec, string))
1532 vector_set (matchvec, desc);
1533 }
1534 }
1535 }
1536 }
1537 }
1538 vector_free (cmd_vector);
1539
1540 if (vector_slot (matchvec, 0) == NULL)
1541 {
1542 vector_free (matchvec);
1543 *status= CMD_ERR_NO_MATCH;
1544 }
1545 else
1546 *status = CMD_SUCCESS;
1547
1548 return matchvec;
1549}
1550
paulb92938a2002-12-13 21:20:42 +00001551vector
1552cmd_describe_command (vector vline, struct vty *vty, int *status)
1553{
1554 vector ret;
1555
1556 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1557 {
1558 enum node_type onode;
1559 vector shifted_vline;
1560 int index;
1561
1562 onode = vty->node;
1563 vty->node = ENABLE_NODE;
1564 /* We can try it on enable node, cos' the vty is authenticated */
1565
1566 shifted_vline = vector_init (vector_count(vline));
1567 /* use memcpy? */
1568 for (index = 1; index < vector_max (vline); index++)
1569 {
1570 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1571 }
1572
1573 ret = cmd_describe_command_real (shifted_vline, vty, status);
1574
1575 vector_free(shifted_vline);
1576 vty->node = onode;
1577 return ret;
1578 }
1579
1580
1581 return cmd_describe_command_real (vline, vty, status);
1582}
1583
1584
pauleda031f2003-01-18 00:39:19 +00001585vector
1586cmd_describe_command (vector vline, struct vty *vty, int *status)
1587{
1588 vector ret;
1589
1590 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1591 {
1592 enum node_type onode;
1593 vector shifted_vline;
1594 int index;
1595
1596 onode = vty->node;
1597 vty->node = ENABLE_NODE;
1598 /* We can try it on enable node, cos' the vty is authenticated */
1599
1600 shifted_vline = vector_init (vector_count(vline));
1601 /* use memcpy? */
1602 for (index = 1; index < vector_max (vline); index++)
1603 {
1604 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1605 }
1606
1607 ret = cmd_describe_command_real (shifted_vline, vty, status);
1608
1609 vector_free(shifted_vline);
1610 vty->node = onode;
1611 return ret;
1612 }
1613
1614
1615 return cmd_describe_command_real (vline, vty, status);
1616}
1617
1618
paul718e3742002-12-13 20:15:29 +00001619/* Check LCD of matched command. */
1620int
1621cmd_lcd (char **matched)
1622{
1623 int i;
1624 int j;
1625 int lcd = -1;
1626 char *s1, *s2;
1627 char c1, c2;
1628
1629 if (matched[0] == NULL || matched[1] == NULL)
1630 return 0;
1631
1632 for (i = 1; matched[i] != NULL; i++)
1633 {
1634 s1 = matched[i - 1];
1635 s2 = matched[i];
1636
1637 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1638 if (c1 != c2)
1639 break;
1640
1641 if (lcd < 0)
1642 lcd = j;
1643 else
1644 {
1645 if (lcd > j)
1646 lcd = j;
1647 }
1648 }
1649 return lcd;
1650}
1651
1652/* Command line completion support. */
1653char **
paulb92938a2002-12-13 21:20:42 +00001654cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001655{
1656 int i;
1657 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1658#define INIT_MATCHVEC_SIZE 10
1659 vector matchvec;
1660 struct cmd_element *cmd_element;
1661 int index = vector_max (vline) - 1;
1662 char **match_str;
1663 struct desc *desc;
1664 vector descvec;
1665 char *command;
1666 int lcd;
1667
1668 /* First, filter by preceeding command string */
1669 for (i = 0; i < index; i++)
1670 {
1671 enum match_type match;
1672 int ret;
1673
1674 command = vector_slot (vline, i);
1675
1676 /* First try completion match, if there is exactly match return 1 */
1677 match = cmd_filter_by_completion (command, cmd_vector, i);
1678
1679 /* If there is exact match then filter ambiguous match else check
1680 ambiguousness. */
1681 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1682 {
1683 vector_free (cmd_vector);
1684 *status = CMD_ERR_AMBIGUOUS;
1685 return NULL;
1686 }
1687 /*
1688 else if (ret == 2)
1689 {
1690 vector_free (cmd_vector);
1691 *status = CMD_ERR_NO_MATCH;
1692 return NULL;
1693 }
1694 */
1695 }
1696
1697 /* Prepare match vector. */
1698 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1699
1700 /* Now we got into completion */
1701 for (i = 0; i < vector_max (cmd_vector); i++)
1702 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1703 {
1704 char *string;
1705 vector strvec = cmd_element->strvec;
1706
1707 /* Check field length */
1708 if (index >= vector_max (strvec))
1709 vector_slot (cmd_vector, i) = NULL;
1710 else
1711 {
1712 int j;
1713
1714 descvec = vector_slot (strvec, index);
1715 for (j = 0; j < vector_max (descvec); j++)
1716 {
1717 desc = vector_slot (descvec, j);
1718
1719 if ((string = cmd_entry_function (vector_slot (vline, index),
1720 desc->cmd)))
1721 if (cmd_unique_string (matchvec, string))
1722 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1723 }
1724 }
1725 }
1726
1727 /* We don't need cmd_vector any more. */
1728 vector_free (cmd_vector);
1729
1730 /* No matched command */
1731 if (vector_slot (matchvec, 0) == NULL)
1732 {
1733 vector_free (matchvec);
1734
1735 /* In case of 'command \t' pattern. Do you need '?' command at
1736 the end of the line. */
1737 if (vector_slot (vline, index) == '\0')
1738 *status = CMD_ERR_NOTHING_TODO;
1739 else
1740 *status = CMD_ERR_NO_MATCH;
1741 return NULL;
1742 }
1743
1744 /* Only one matched */
1745 if (vector_slot (matchvec, 1) == NULL)
1746 {
1747 match_str = (char **) matchvec->index;
1748 vector_only_wrapper_free (matchvec);
1749 *status = CMD_COMPLETE_FULL_MATCH;
1750 return match_str;
1751 }
1752 /* Make it sure last element is NULL. */
1753 vector_set (matchvec, NULL);
1754
1755 /* Check LCD of matched strings. */
1756 if (vector_slot (vline, index) != NULL)
1757 {
1758 lcd = cmd_lcd ((char **) matchvec->index);
1759
1760 if (lcd)
1761 {
1762 int len = strlen (vector_slot (vline, index));
1763
1764 if (len < lcd)
1765 {
1766 char *lcdstr;
1767
1768 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1769 memcpy (lcdstr, matchvec->index[0], lcd);
1770 lcdstr[lcd] = '\0';
1771
1772 /* match_str = (char **) &lcdstr; */
1773
1774 /* Free matchvec. */
1775 for (i = 0; i < vector_max (matchvec); i++)
1776 {
1777 if (vector_slot (matchvec, i))
1778 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1779 }
1780 vector_free (matchvec);
1781
1782 /* Make new matchvec. */
1783 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1784 vector_set (matchvec, lcdstr);
1785 match_str = (char **) matchvec->index;
1786 vector_only_wrapper_free (matchvec);
1787
1788 *status = CMD_COMPLETE_MATCH;
1789 return match_str;
1790 }
1791 }
1792 }
1793
1794 match_str = (char **) matchvec->index;
1795 vector_only_wrapper_free (matchvec);
1796 *status = CMD_COMPLETE_LIST_MATCH;
1797 return match_str;
1798}
1799
paulb92938a2002-12-13 21:20:42 +00001800char **
pauleda031f2003-01-18 00:39:19 +00001801cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001802{
1803 char **ret;
1804
1805 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1806 {
1807 enum node_type onode;
1808 vector shifted_vline;
1809 int index;
1810
1811 onode = vty->node;
1812 vty->node = ENABLE_NODE;
1813 /* We can try it on enable node, cos' the vty is authenticated */
1814
1815 shifted_vline = vector_init (vector_count(vline));
1816 /* use memcpy? */
1817 for (index = 1; index < vector_max (vline); index++)
1818 {
1819 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1820 }
1821
1822 ret = cmd_complete_command_real (shifted_vline, vty, status);
1823
1824 vector_free(shifted_vline);
1825 vty->node = onode;
1826 return ret;
1827 }
1828
1829
1830 return cmd_complete_command_real (vline, vty, status);
1831}
1832
1833/* return parent node */
1834/* MUST eventually converge on CONFIG_NODE */
1835enum node_type node_parent ( enum node_type node )
1836{
1837 enum node_type ret;
1838
1839 switch ( node ) {
1840 case KEYCHAIN_KEY_NODE:
1841 ret = KEYCHAIN_NODE;
1842 break;
1843 default:
1844 ret = CONFIG_NODE;
1845 }
1846
1847 return ret;
1848}
1849
paul718e3742002-12-13 20:15:29 +00001850/* Execute command by argument vline vector. */
1851int
paulb92938a2002-12-13 21:20:42 +00001852cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001853{
1854 int i;
1855 int index;
1856 vector cmd_vector;
1857 struct cmd_element *cmd_element;
1858 struct cmd_element *matched_element;
1859 unsigned int matched_count, incomplete_count;
1860 int argc;
1861 char *argv[CMD_ARGC_MAX];
1862 enum match_type match = 0;
1863 int varflag;
1864 char *command;
1865
1866 /* Make copy of command elements. */
1867 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1868
1869 for (index = 0; index < vector_max (vline); index++)
1870 {
1871 int ret;
1872
1873 command = vector_slot (vline, index);
1874
1875 match = cmd_filter_by_completion (command, cmd_vector, index);
1876
1877 if (match == vararg_match)
1878 break;
1879
1880 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1881
1882 if (ret == 1)
1883 {
1884 vector_free (cmd_vector);
1885 return CMD_ERR_AMBIGUOUS;
1886 }
1887 else if (ret == 2)
1888 {
1889 vector_free (cmd_vector);
1890 return CMD_ERR_NO_MATCH;
1891 }
1892 }
1893
1894 /* Check matched count. */
1895 matched_element = NULL;
1896 matched_count = 0;
1897 incomplete_count = 0;
1898
1899 for (i = 0; i < vector_max (cmd_vector); i++)
1900 if (vector_slot (cmd_vector,i) != NULL)
1901 {
1902 cmd_element = vector_slot (cmd_vector,i);
1903
1904 if (match == vararg_match || index >= cmd_element->cmdsize)
1905 {
1906 matched_element = cmd_element;
1907#if 0
1908 printf ("DEBUG: %s\n", cmd_element->string);
1909#endif
1910 matched_count++;
1911 }
1912 else
1913 {
1914 incomplete_count++;
1915 }
1916 }
1917
1918 /* Finish of using cmd_vector. */
1919 vector_free (cmd_vector);
1920
1921 /* To execute command, matched_count must be 1.*/
1922 if (matched_count == 0)
1923 {
1924 if (incomplete_count)
1925 return CMD_ERR_INCOMPLETE;
1926 else
1927 return CMD_ERR_NO_MATCH;
1928 }
1929
1930 if (matched_count > 1)
1931 return CMD_ERR_AMBIGUOUS;
1932
1933 /* Argument treatment */
1934 varflag = 0;
1935 argc = 0;
1936
1937 for (i = 0; i < vector_max (vline); i++)
1938 {
1939 if (varflag)
1940 argv[argc++] = vector_slot (vline, i);
1941 else
1942 {
1943 vector descvec = vector_slot (matched_element->strvec, i);
1944
1945 if (vector_max (descvec) == 1)
1946 {
1947 struct desc *desc = vector_slot (descvec, 0);
1948 char *str = desc->cmd;
1949
1950 if (CMD_VARARG (str))
1951 varflag = 1;
1952
1953 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
1954 argv[argc++] = vector_slot (vline, i);
1955 }
1956 else
1957 argv[argc++] = vector_slot (vline, i);
1958 }
1959
1960 if (argc >= CMD_ARGC_MAX)
1961 return CMD_ERR_EXEED_ARGC_MAX;
1962 }
1963
1964 /* For vtysh execution. */
1965 if (cmd)
1966 *cmd = matched_element;
1967
1968 if (matched_element->daemon)
1969 return CMD_SUCCESS_DAEMON;
1970
1971 /* Execute matched command. */
1972 return (*matched_element->func) (matched_element, vty, argc, argv);
1973}
1974
paulb92938a2002-12-13 21:20:42 +00001975
1976int
1977cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
1978 int ret;
1979 enum node_type onode = vty->node;
1980
1981 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1982 {
1983 vector shifted_vline;
1984 int index;
1985
1986 vty->node = ENABLE_NODE;
1987 /* We can try it on enable node, cos' the vty is authenticated */
1988
1989 shifted_vline = vector_init (vector_count(vline));
1990 /* use memcpy? */
1991 for (index = 1; index < vector_max (vline); index++)
1992 {
1993 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1994 }
1995
1996 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
1997
1998 vector_free(shifted_vline);
1999 vty->node = onode;
2000 return ret;
2001 }
2002
2003
2004 ret = cmd_execute_command_real (vline, vty, cmd);
2005
2006 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2007 if ( ret != CMD_SUCCESS && ret != CMD_WARNING
2008 && vty->node > CONFIG_NODE )
2009 {
2010 /* XXX try node_parent(vty->node)? */
2011 vty->node = CONFIG_NODE;
2012 ret = cmd_execute_command_real (vline, vty, cmd);
2013 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
2014 {
2015 /* if the command changed the node dont reset it */
2016 if( vty->node == CONFIG_NODE )
2017 vty->node = onode;
2018 return ret;
2019 }
2020 else
2021 if( vty->node == CONFIG_NODE )
2022 vty->node = onode;
2023 /* if the command changed the node dont reset it */
2024 }
2025 return ret;
2026}
2027
pauleda031f2003-01-18 00:39:19 +00002028
2029int
2030cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
2031 int ret;
2032 enum node_type onode = vty->node;
2033
2034 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2035 {
2036 vector shifted_vline;
2037 int index;
2038
2039 vty->node = ENABLE_NODE;
2040 /* We can try it on enable node, cos' the vty is authenticated */
2041
2042 shifted_vline = vector_init (vector_count(vline));
2043 /* use memcpy? */
2044 for (index = 1; index < vector_max (vline); index++)
2045 {
2046 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2047 }
2048
2049 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2050
2051 vector_free(shifted_vline);
2052 vty->node = onode;
2053 return ret;
2054 }
2055
2056
2057 ret = cmd_execute_command_real (vline, vty, cmd);
2058
2059 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2060 if ( ret != CMD_SUCCESS && ret != CMD_WARNING
2061 && vty->node > CONFIG_NODE )
2062 {
2063 /* XXX try node_parent(vty->node)? */
2064 vty->node = CONFIG_NODE;
2065 ret = cmd_execute_command_real (vline, vty, cmd);
2066 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
2067 {
2068 /* if the command changed the node dont reset it */
2069 if( vty->node == CONFIG_NODE )
2070 vty->node = onode;
2071 return ret;
2072 }
2073 else
2074 if( vty->node == CONFIG_NODE )
2075 vty->node = onode;
2076 /* if the command changed the node dont reset it */
2077 }
2078 return ret;
2079}
2080
paul718e3742002-12-13 20:15:29 +00002081/* Execute command by argument readline. */
2082int
2083cmd_execute_command_strict (vector vline, struct vty *vty,
2084 struct cmd_element **cmd)
2085{
2086 int i;
2087 int index;
2088 vector cmd_vector;
2089 struct cmd_element *cmd_element;
2090 struct cmd_element *matched_element;
2091 unsigned int matched_count, incomplete_count;
2092 int argc;
2093 char *argv[CMD_ARGC_MAX];
2094 int varflag;
2095 enum match_type match = 0;
2096 char *command;
2097
2098 /* Make copy of command element */
2099 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2100
2101 for (index = 0; index < vector_max (vline); index++)
2102 {
2103 int ret;
2104
2105 command = vector_slot (vline, index);
2106
2107 match = cmd_filter_by_string (vector_slot (vline, index),
2108 cmd_vector, index);
2109
2110 /* If command meets '.VARARG' then finish matching. */
2111 if (match == vararg_match)
2112 break;
2113
2114 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2115 if (ret == 1)
2116 {
2117 vector_free (cmd_vector);
2118 return CMD_ERR_AMBIGUOUS;
2119 }
2120 if (ret == 2)
2121 {
2122 vector_free (cmd_vector);
2123 return CMD_ERR_NO_MATCH;
2124 }
2125 }
2126
2127 /* Check matched count. */
2128 matched_element = NULL;
2129 matched_count = 0;
2130 incomplete_count = 0;
2131 for (i = 0; i < vector_max (cmd_vector); i++)
2132 if (vector_slot (cmd_vector,i) != NULL)
2133 {
2134 cmd_element = vector_slot (cmd_vector,i);
2135
2136 if (match == vararg_match || index >= cmd_element->cmdsize)
2137 {
2138 matched_element = cmd_element;
2139 matched_count++;
2140 }
2141 else
2142 incomplete_count++;
2143 }
2144
2145 /* Finish of using cmd_vector. */
2146 vector_free (cmd_vector);
2147
2148 /* To execute command, matched_count must be 1.*/
2149 if (matched_count == 0)
2150 {
2151 if (incomplete_count)
2152 return CMD_ERR_INCOMPLETE;
2153 else
2154 return CMD_ERR_NO_MATCH;
2155 }
2156
2157 if (matched_count > 1)
2158 return CMD_ERR_AMBIGUOUS;
2159
2160 /* Argument treatment */
2161 varflag = 0;
2162 argc = 0;
2163
2164 for (i = 0; i < vector_max (vline); i++)
2165 {
2166 if (varflag)
2167 argv[argc++] = vector_slot (vline, i);
2168 else
2169 {
2170 vector descvec = vector_slot (matched_element->strvec, i);
2171
2172 if (vector_max (descvec) == 1)
2173 {
2174 struct desc *desc = vector_slot (descvec, 0);
2175 char *str = desc->cmd;
2176
2177 if (CMD_VARARG (str))
2178 varflag = 1;
2179
2180 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
2181 argv[argc++] = vector_slot (vline, i);
2182 }
2183 else
2184 argv[argc++] = vector_slot (vline, i);
2185 }
2186
2187 if (argc >= CMD_ARGC_MAX)
2188 return CMD_ERR_EXEED_ARGC_MAX;
2189 }
2190
2191 /* For vtysh execution. */
2192 if (cmd)
2193 *cmd = matched_element;
2194
2195 if (matched_element->daemon)
2196 return CMD_SUCCESS_DAEMON;
2197
2198 /* Now execute matched command */
2199 return (*matched_element->func) (matched_element, vty, argc, argv);
2200}
2201
2202/* Configration make from file. */
2203int
2204config_from_file (struct vty *vty, FILE *fp)
2205{
2206 int ret;
2207 vector vline;
2208
2209 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2210 {
2211 vline = cmd_make_strvec (vty->buf);
2212
2213 /* In case of comment line */
2214 if (vline == NULL)
2215 continue;
2216 /* Execute configuration command : this is strict match */
2217 ret = cmd_execute_command_strict (vline, vty, NULL);
2218
2219 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002220 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2221 && vty->node != CONFIG_NODE)
paul718e3742002-12-13 20:15:29 +00002222 {
paulb92938a2002-12-13 21:20:42 +00002223 vty->node = node_parent(vty->node);
2224 ret = cmd_execute_command_strict (vline, vty, NULL);
paul718e3742002-12-13 20:15:29 +00002225 }
paulb92938a2002-12-13 21:20:42 +00002226
paul718e3742002-12-13 20:15:29 +00002227 cmd_free_strvec (vline);
2228
2229 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
2230 return ret;
2231 }
2232 return CMD_SUCCESS;
2233}
2234
2235/* Configration from terminal */
2236DEFUN (config_terminal,
2237 config_terminal_cmd,
2238 "configure terminal",
2239 "Configuration from vty interface\n"
2240 "Configuration terminal\n")
2241{
2242 if (vty_config_lock (vty))
2243 vty->node = CONFIG_NODE;
2244 else
2245 {
2246 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2247 return CMD_WARNING;
2248 }
2249 return CMD_SUCCESS;
2250}
2251
2252/* Enable command */
2253DEFUN (enable,
2254 config_enable_cmd,
2255 "enable",
2256 "Turn on privileged mode command\n")
2257{
2258 /* If enable password is NULL, change to ENABLE_NODE */
2259 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2260 vty->type == VTY_SHELL_SERV)
2261 vty->node = ENABLE_NODE;
2262 else
2263 vty->node = AUTH_ENABLE_NODE;
2264
2265 return CMD_SUCCESS;
2266}
2267
2268/* Disable command */
2269DEFUN (disable,
2270 config_disable_cmd,
2271 "disable",
2272 "Turn off privileged mode command\n")
2273{
2274 if (vty->node == ENABLE_NODE)
2275 vty->node = VIEW_NODE;
2276 return CMD_SUCCESS;
2277}
2278
2279/* Down vty node level. */
2280DEFUN (config_exit,
2281 config_exit_cmd,
2282 "exit",
2283 "Exit current mode and down to previous mode\n")
2284{
2285 switch (vty->node)
2286 {
2287 case VIEW_NODE:
2288 case ENABLE_NODE:
2289 if (vty_shell (vty))
2290 exit (0);
2291 else
2292 vty->status = VTY_CLOSE;
2293 break;
2294 case CONFIG_NODE:
2295 vty->node = ENABLE_NODE;
2296 vty_config_unlock (vty);
2297 break;
2298 case INTERFACE_NODE:
2299 case ZEBRA_NODE:
2300 case BGP_NODE:
2301 case RIP_NODE:
2302 case RIPNG_NODE:
2303 case OSPF_NODE:
2304 case OSPF6_NODE:
2305 case KEYCHAIN_NODE:
2306 case MASC_NODE:
2307 case RMAP_NODE:
2308 case VTY_NODE:
2309 vty->node = CONFIG_NODE;
2310 break;
2311 case BGP_VPNV4_NODE:
2312 case BGP_IPV4_NODE:
2313 case BGP_IPV4M_NODE:
2314 case BGP_IPV6_NODE:
2315 vty->node = BGP_NODE;
2316 break;
2317 case KEYCHAIN_KEY_NODE:
2318 vty->node = KEYCHAIN_NODE;
2319 break;
2320 default:
2321 break;
2322 }
2323 return CMD_SUCCESS;
2324}
2325
2326/* quit is alias of exit. */
2327ALIAS (config_exit,
2328 config_quit_cmd,
2329 "quit",
2330 "Exit current mode and down to previous mode\n")
2331
2332/* End of configuration. */
2333DEFUN (config_end,
2334 config_end_cmd,
2335 "end",
2336 "End current mode and change to enable mode.")
2337{
2338 switch (vty->node)
2339 {
2340 case VIEW_NODE:
2341 case ENABLE_NODE:
2342 /* Nothing to do. */
2343 break;
2344 case CONFIG_NODE:
2345 case INTERFACE_NODE:
2346 case ZEBRA_NODE:
2347 case RIP_NODE:
2348 case RIPNG_NODE:
2349 case BGP_NODE:
2350 case BGP_VPNV4_NODE:
2351 case BGP_IPV4_NODE:
2352 case BGP_IPV4M_NODE:
2353 case BGP_IPV6_NODE:
2354 case RMAP_NODE:
2355 case OSPF_NODE:
2356 case OSPF6_NODE:
2357 case KEYCHAIN_NODE:
2358 case KEYCHAIN_KEY_NODE:
2359 case MASC_NODE:
2360 case VTY_NODE:
2361 vty_config_unlock (vty);
2362 vty->node = ENABLE_NODE;
2363 break;
2364 default:
2365 break;
2366 }
2367 return CMD_SUCCESS;
2368}
2369
2370/* Show version. */
2371DEFUN (show_version,
2372 show_version_cmd,
2373 "show version",
2374 SHOW_STR
2375 "Displays zebra version\n")
2376{
2377 vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
2378 host_name,
2379 VTY_NEWLINE);
2380 vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
2381
2382 return CMD_SUCCESS;
2383}
2384
2385/* Help display function for all node. */
2386DEFUN (config_help,
2387 config_help_cmd,
2388 "help",
2389 "Description of the interactive help system\n")
2390{
2391 vty_out (vty,
2392 "Zebra VTY provides advanced help feature. When you need help,%s\
2393anytime at the command line please press '?'.%s\
2394%s\
2395If nothing matches, the help list will be empty and you must backup%s\
2396 until entering a '?' shows the available options.%s\
2397Two styles of help are provided:%s\
23981. Full help is available when you are ready to enter a%s\
2399command argument (e.g. 'show ?') and describes each possible%s\
2400argument.%s\
24012. Partial help is provided when an abbreviated argument is entered%s\
2402 and you want to know what arguments match the input%s\
2403 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2404 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2405 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2406 return CMD_SUCCESS;
2407}
2408
2409/* Help display function for all node. */
2410DEFUN (config_list,
2411 config_list_cmd,
2412 "list",
2413 "Print command list\n")
2414{
2415 int i;
2416 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2417 struct cmd_element *cmd;
2418
2419 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2420 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2421 vty_out (vty, " %s%s", cmd->string,
2422 VTY_NEWLINE);
2423 return CMD_SUCCESS;
2424}
2425
2426/* Write current configuration into file. */
2427DEFUN (config_write_file,
2428 config_write_file_cmd,
2429 "write file",
2430 "Write running configuration to memory, network, or terminal\n"
2431 "Write to configuration file\n")
2432{
2433 int i;
2434 int fd;
2435 struct cmd_node *node;
2436 char *config_file;
2437 char *config_file_tmp = NULL;
2438 char *config_file_sav = NULL;
2439 struct vty *file_vty;
2440
2441 /* Check and see if we are operating under vtysh configuration */
2442 if (host.config == NULL)
2443 {
2444 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2445 VTY_NEWLINE);
2446 return CMD_WARNING;
2447 }
2448
2449 /* Get filename. */
2450 config_file = host.config;
2451
2452 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2453 strcpy (config_file_sav, config_file);
2454 strcat (config_file_sav, CONF_BACKUP_EXT);
2455
2456
2457 config_file_tmp = malloc (strlen (config_file) + 8);
2458 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2459
2460 /* Open file to configuration write. */
2461 fd = mkstemp (config_file_tmp);
2462 if (fd < 0)
2463 {
2464 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2465 VTY_NEWLINE);
2466 free (config_file_tmp);
2467 free (config_file_sav);
2468 return CMD_WARNING;
2469 }
2470
2471 /* Make vty for configuration file. */
2472 file_vty = vty_new ();
2473 file_vty->fd = fd;
2474 file_vty->type = VTY_FILE;
2475
2476 /* Config file header print. */
2477 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2478 vty_time_print (file_vty, 1);
2479 vty_out (file_vty, "!\n");
2480
2481 for (i = 0; i < vector_max (cmdvec); i++)
2482 if ((node = vector_slot (cmdvec, i)) && node->func)
2483 {
2484 if ((*node->func) (file_vty))
2485 vty_out (file_vty, "!\n");
2486 }
2487 vty_close (file_vty);
2488
2489 if (unlink (config_file_sav) != 0)
2490 if (errno != ENOENT)
2491 {
2492 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2493 VTY_NEWLINE);
2494 free (config_file_sav);
2495 free (config_file_tmp);
2496 unlink (config_file_tmp);
2497 return CMD_WARNING;
2498 }
2499 if (link (config_file, config_file_sav) != 0)
2500 {
2501 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2502 VTY_NEWLINE);
2503 free (config_file_sav);
2504 free (config_file_tmp);
2505 unlink (config_file_tmp);
2506 return CMD_WARNING;
2507 }
2508 sync ();
2509 if (unlink (config_file) != 0)
2510 {
2511 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2512 VTY_NEWLINE);
2513 free (config_file_sav);
2514 free (config_file_tmp);
2515 unlink (config_file_tmp);
2516 return CMD_WARNING;
2517 }
2518 if (link (config_file_tmp, config_file) != 0)
2519 {
2520 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2521 VTY_NEWLINE);
2522 free (config_file_sav);
2523 free (config_file_tmp);
2524 unlink (config_file_tmp);
2525 return CMD_WARNING;
2526 }
2527 unlink (config_file_tmp);
2528 sync ();
2529
2530 free (config_file_sav);
2531 free (config_file_tmp);
2532 vty_out (vty, "Configuration saved to %s%s", config_file,
2533 VTY_NEWLINE);
2534 return CMD_SUCCESS;
2535}
2536
2537ALIAS (config_write_file,
2538 config_write_cmd,
2539 "write",
2540 "Write running configuration to memory, network, or terminal\n")
2541
2542ALIAS (config_write_file,
2543 config_write_memory_cmd,
2544 "write memory",
2545 "Write running configuration to memory, network, or terminal\n"
2546 "Write configuration to the file (same as write file)\n")
2547
2548ALIAS (config_write_file,
2549 copy_runningconfig_startupconfig_cmd,
2550 "copy running-config startup-config",
2551 "Copy configuration\n"
2552 "Copy running config to... \n"
2553 "Copy running config to startup config (same as write file)\n")
2554
2555/* Write current configuration into the terminal. */
2556DEFUN (config_write_terminal,
2557 config_write_terminal_cmd,
2558 "write terminal",
2559 "Write running configuration to memory, network, or terminal\n"
2560 "Write to terminal\n")
2561{
2562 int i;
2563 struct cmd_node *node;
2564
2565 if (vty->type == VTY_SHELL_SERV)
2566 {
2567 for (i = 0; i < vector_max (cmdvec); i++)
2568 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2569 {
2570 if ((*node->func) (vty))
2571 vty_out (vty, "!%s", VTY_NEWLINE);
2572 }
2573 }
2574 else
2575 {
2576 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2577 VTY_NEWLINE);
2578 vty_out (vty, "!%s", VTY_NEWLINE);
2579
2580 for (i = 0; i < vector_max (cmdvec); i++)
2581 if ((node = vector_slot (cmdvec, i)) && node->func)
2582 {
2583 if ((*node->func) (vty))
2584 vty_out (vty, "!%s", VTY_NEWLINE);
2585 }
2586 vty_out (vty, "end%s",VTY_NEWLINE);
2587 }
2588 return CMD_SUCCESS;
2589}
2590
2591/* Write current configuration into the terminal. */
2592ALIAS (config_write_terminal,
2593 show_running_config_cmd,
2594 "show running-config",
2595 SHOW_STR
2596 "running configuration\n")
2597
2598/* Write startup configuration into the terminal. */
2599DEFUN (show_startup_config,
2600 show_startup_config_cmd,
2601 "show startup-config",
2602 SHOW_STR
2603 "Contentes of startup configuration\n")
2604{
2605 char buf[BUFSIZ];
2606 FILE *confp;
2607
2608 confp = fopen (host.config, "r");
2609 if (confp == NULL)
2610 {
2611 vty_out (vty, "Can't open configuration file [%s]%s",
2612 host.config, VTY_NEWLINE);
2613 return CMD_WARNING;
2614 }
2615
2616 while (fgets (buf, BUFSIZ, confp))
2617 {
2618 char *cp = buf;
2619
2620 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2621 cp++;
2622 *cp = '\0';
2623
2624 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2625 }
2626
2627 fclose (confp);
2628
2629 return CMD_SUCCESS;
2630}
2631
2632/* Hostname configuration */
2633DEFUN (config_hostname,
2634 hostname_cmd,
2635 "hostname WORD",
2636 "Set system's network name\n"
2637 "This system's network name\n")
2638{
2639 if (!isalpha((int) *argv[0]))
2640 {
2641 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2642 return CMD_WARNING;
2643 }
2644
2645 if (host.name)
2646 XFREE (0, host.name);
2647
2648 host.name = strdup (argv[0]);
2649 return CMD_SUCCESS;
2650}
2651
2652DEFUN (config_no_hostname,
2653 no_hostname_cmd,
2654 "no hostname [HOSTNAME]",
2655 NO_STR
2656 "Reset system's network name\n"
2657 "Host name of this router\n")
2658{
2659 if (host.name)
2660 XFREE (0, host.name);
2661 host.name = NULL;
2662 return CMD_SUCCESS;
2663}
2664
2665/* VTY interface password set. */
2666DEFUN (config_password, password_cmd,
2667 "password (8|) WORD",
2668 "Assign the terminal connection password\n"
2669 "Specifies a HIDDEN password will follow\n"
2670 "dummy string \n"
2671 "The HIDDEN line password string\n")
2672{
2673 /* Argument check. */
2674 if (argc == 0)
2675 {
2676 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2677 return CMD_WARNING;
2678 }
2679
2680 if (argc == 2)
2681 {
2682 if (*argv[0] == '8')
2683 {
2684 if (host.password)
2685 XFREE (0, host.password);
2686 host.password = NULL;
2687 if (host.password_encrypt)
2688 XFREE (0, host.password_encrypt);
2689 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2690 return CMD_SUCCESS;
2691 }
2692 else
2693 {
2694 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2695 return CMD_WARNING;
2696 }
2697 }
2698
2699 if (!isalnum ((int) *argv[0]))
2700 {
2701 vty_out (vty,
2702 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2703 return CMD_WARNING;
2704 }
2705
2706 if (host.password)
2707 XFREE (0, host.password);
2708 host.password = NULL;
2709
2710 if (host.encrypt)
2711 {
2712 if (host.password_encrypt)
2713 XFREE (0, host.password_encrypt);
2714 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2715 }
2716 else
2717 host.password = XSTRDUP (0, argv[0]);
2718
2719 return CMD_SUCCESS;
2720}
2721
2722ALIAS (config_password, password_text_cmd,
2723 "password LINE",
2724 "Assign the terminal connection password\n"
2725 "The UNENCRYPTED (cleartext) line password\n")
2726
2727/* VTY enable password set. */
2728DEFUN (config_enable_password, enable_password_cmd,
2729 "enable password (8|) WORD",
2730 "Modify enable password parameters\n"
2731 "Assign the privileged level password\n"
2732 "Specifies a HIDDEN password will follow\n"
2733 "dummy string \n"
2734 "The HIDDEN 'enable' password string\n")
2735{
2736 /* Argument check. */
2737 if (argc == 0)
2738 {
2739 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2740 return CMD_WARNING;
2741 }
2742
2743 /* Crypt type is specified. */
2744 if (argc == 2)
2745 {
2746 if (*argv[0] == '8')
2747 {
2748 if (host.enable)
2749 XFREE (0, host.enable);
2750 host.enable = NULL;
2751
2752 if (host.enable_encrypt)
2753 XFREE (0, host.enable_encrypt);
2754 host.enable_encrypt = XSTRDUP (0, argv[1]);
2755
2756 return CMD_SUCCESS;
2757 }
2758 else
2759 {
2760 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2761 return CMD_WARNING;
2762 }
2763 }
2764
2765 if (!isalnum ((int) *argv[0]))
2766 {
2767 vty_out (vty,
2768 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2769 return CMD_WARNING;
2770 }
2771
2772 if (host.enable)
2773 XFREE (0, host.enable);
2774 host.enable = NULL;
2775
2776 /* Plain password input. */
2777 if (host.encrypt)
2778 {
2779 if (host.enable_encrypt)
2780 XFREE (0, host.enable_encrypt);
2781 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2782 }
2783 else
2784 host.enable = XSTRDUP (0, argv[0]);
2785
2786 return CMD_SUCCESS;
2787}
2788
2789ALIAS (config_enable_password,
2790 enable_password_text_cmd,
2791 "enable password LINE",
2792 "Modify enable password parameters\n"
2793 "Assign the privileged level password\n"
2794 "The UNENCRYPTED (cleartext) 'enable' password\n")
2795
2796/* VTY enable password delete. */
2797DEFUN (no_config_enable_password, no_enable_password_cmd,
2798 "no enable password",
2799 NO_STR
2800 "Modify enable password parameters\n"
2801 "Assign the privileged level password\n")
2802{
2803 if (host.enable)
2804 XFREE (0, host.enable);
2805 host.enable = NULL;
2806
2807 if (host.enable_encrypt)
2808 XFREE (0, host.enable_encrypt);
2809 host.enable_encrypt = NULL;
2810
2811 return CMD_SUCCESS;
2812}
2813
2814DEFUN (service_password_encrypt,
2815 service_password_encrypt_cmd,
2816 "service password-encryption",
2817 "Set up miscellaneous service\n"
2818 "Enable encrypted passwords\n")
2819{
2820 if (host.encrypt)
2821 return CMD_SUCCESS;
2822
2823 host.encrypt = 1;
2824
2825 if (host.password)
2826 {
2827 if (host.password_encrypt)
2828 XFREE (0, host.password_encrypt);
2829 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2830 }
2831 if (host.enable)
2832 {
2833 if (host.enable_encrypt)
2834 XFREE (0, host.enable_encrypt);
2835 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2836 }
2837
2838 return CMD_SUCCESS;
2839}
2840
2841DEFUN (no_service_password_encrypt,
2842 no_service_password_encrypt_cmd,
2843 "no service password-encryption",
2844 NO_STR
2845 "Set up miscellaneous service\n"
2846 "Enable encrypted passwords\n")
2847{
2848 if (! host.encrypt)
2849 return CMD_SUCCESS;
2850
2851 host.encrypt = 0;
2852
2853 if (host.password_encrypt)
2854 XFREE (0, host.password_encrypt);
2855 host.password_encrypt = NULL;
2856
2857 if (host.enable_encrypt)
2858 XFREE (0, host.enable_encrypt);
2859 host.enable_encrypt = NULL;
2860
2861 return CMD_SUCCESS;
2862}
2863
2864DEFUN (config_terminal_length, config_terminal_length_cmd,
2865 "terminal length <0-512>",
2866 "Set terminal line parameters\n"
2867 "Set number of lines on a screen\n"
2868 "Number of lines on screen (0 for no pausing)\n")
2869{
2870 int lines;
2871 char *endptr = NULL;
2872
2873 lines = strtol (argv[0], &endptr, 10);
2874 if (lines < 0 || lines > 512 || *endptr != '\0')
2875 {
2876 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2877 return CMD_WARNING;
2878 }
2879 vty->lines = lines;
2880
2881 return CMD_SUCCESS;
2882}
2883
2884DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2885 "terminal no length",
2886 "Set terminal line parameters\n"
2887 NO_STR
2888 "Set number of lines on a screen\n")
2889{
2890 vty->lines = -1;
2891 return CMD_SUCCESS;
2892}
2893
2894DEFUN (service_terminal_length, service_terminal_length_cmd,
2895 "service terminal-length <0-512>",
2896 "Set up miscellaneous service\n"
2897 "System wide terminal length configuration\n"
2898 "Number of lines of VTY (0 means no line control)\n")
2899{
2900 int lines;
2901 char *endptr = NULL;
2902
2903 lines = strtol (argv[0], &endptr, 10);
2904 if (lines < 0 || lines > 512 || *endptr != '\0')
2905 {
2906 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2907 return CMD_WARNING;
2908 }
2909 host.lines = lines;
2910
2911 return CMD_SUCCESS;
2912}
2913
2914DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2915 "no service terminal-length [<0-512>]",
2916 NO_STR
2917 "Set up miscellaneous service\n"
2918 "System wide terminal length configuration\n"
2919 "Number of lines of VTY (0 means no line control)\n")
2920{
2921 host.lines = -1;
2922 return CMD_SUCCESS;
2923}
2924
2925DEFUN (config_log_stdout,
2926 config_log_stdout_cmd,
2927 "log stdout",
2928 "Logging control\n"
2929 "Logging goes to stdout\n")
2930{
2931 zlog_set_flag (NULL, ZLOG_STDOUT);
2932 host.log_stdout = 1;
2933 return CMD_SUCCESS;
2934}
2935
2936DEFUN (no_config_log_stdout,
2937 no_config_log_stdout_cmd,
2938 "no log stdout",
2939 NO_STR
2940 "Logging control\n"
2941 "Cancel logging to stdout\n")
2942{
2943 zlog_reset_flag (NULL, ZLOG_STDOUT);
2944 host.log_stdout = 0;
2945 return CMD_SUCCESS;
2946}
2947
2948DEFUN (config_log_file,
2949 config_log_file_cmd,
2950 "log file FILENAME",
2951 "Logging control\n"
2952 "Logging to file\n"
2953 "Logging filename\n")
2954{
2955 int ret;
2956 char *cwd;
2957 char *fullpath;
2958
2959 /* Path detection. */
2960 if (! IS_DIRECTORY_SEP (*argv[0]))
2961 {
2962 cwd = getcwd (NULL, MAXPATHLEN);
2963 fullpath = XMALLOC (MTYPE_TMP,
2964 strlen (cwd) + strlen (argv[0]) + 2);
2965 sprintf (fullpath, "%s/%s", cwd, argv[0]);
2966 }
2967 else
2968 fullpath = argv[0];
2969
2970 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
2971
2972 if (!ret)
2973 {
2974 vty_out (vty, "can't open logfile %s\n", argv[0]);
2975 return CMD_WARNING;
2976 }
2977
2978 if (host.logfile)
2979 XFREE (MTYPE_TMP, host.logfile);
2980
2981 host.logfile = strdup (argv[0]);
2982
2983 return CMD_SUCCESS;
2984}
2985
2986DEFUN (no_config_log_file,
2987 no_config_log_file_cmd,
2988 "no log file [FILENAME]",
2989 NO_STR
2990 "Logging control\n"
2991 "Cancel logging to file\n"
2992 "Logging file name\n")
2993{
2994 zlog_reset_file (NULL);
2995
2996 if (host.logfile)
2997 XFREE (MTYPE_TMP, host.logfile);
2998
2999 host.logfile = NULL;
3000
3001 return CMD_SUCCESS;
3002}
3003
3004DEFUN (config_log_syslog,
3005 config_log_syslog_cmd,
3006 "log syslog",
3007 "Logging control\n"
3008 "Logging goes to syslog\n")
3009{
3010 zlog_set_flag (NULL, ZLOG_SYSLOG);
3011 host.log_syslog = 1;
3012 return CMD_SUCCESS;
3013}
3014
3015DEFUN (no_config_log_syslog,
3016 no_config_log_syslog_cmd,
3017 "no log syslog",
3018 NO_STR
3019 "Logging control\n"
3020 "Cancel logging to syslog\n")
3021{
3022 zlog_reset_flag (NULL, ZLOG_SYSLOG);
3023 host.log_syslog = 0;
3024 return CMD_SUCCESS;
3025}
3026
3027DEFUN (config_log_trap,
3028 config_log_trap_cmd,
3029 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3030 "Logging control\n"
3031 "Limit logging to specifed level\n")
3032{
3033 int new_level ;
3034
3035 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
3036 {
3037 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
3038 /* found new logging level */
3039 {
3040 zlog_default->maskpri = new_level;
3041 return CMD_SUCCESS;
3042 }
3043 }
3044 return CMD_ERR_NO_MATCH;
3045}
3046
3047DEFUN (no_config_log_trap,
3048 no_config_log_trap_cmd,
3049 "no log trap",
3050 NO_STR
3051 "Logging control\n"
3052 "Permit all logging information\n")
3053{
3054 zlog_default->maskpri = LOG_DEBUG;
3055 return CMD_SUCCESS;
3056}
3057
3058DEFUN (config_log_record_priority,
3059 config_log_record_priority_cmd,
3060 "log record-priority",
3061 "Logging control\n"
3062 "Log the priority of the message within the message\n")
3063{
3064 zlog_default->record_priority = 1 ;
3065 return CMD_SUCCESS;
3066}
3067
3068DEFUN (no_config_log_record_priority,
3069 no_config_log_record_priority_cmd,
3070 "no log record-priority",
3071 NO_STR
3072 "Logging control\n"
3073 "Do not log the priority of the message within the message\n")
3074{
3075 zlog_default->record_priority = 0 ;
3076 return CMD_SUCCESS;
3077}
3078
3079
3080DEFUN (banner_motd_default,
3081 banner_motd_default_cmd,
3082 "banner motd default",
3083 "Set banner string\n"
3084 "Strings for motd\n"
3085 "Default string\n")
3086{
3087 host.motd = default_motd;
3088 return CMD_SUCCESS;
3089}
3090
3091DEFUN (no_banner_motd,
3092 no_banner_motd_cmd,
3093 "no banner motd",
3094 NO_STR
3095 "Set banner string\n"
3096 "Strings for motd\n")
3097{
3098 host.motd = NULL;
3099 return CMD_SUCCESS;
3100}
3101
3102/* Set config filename. Called from vty.c */
3103void
3104host_config_set (char *filename)
3105{
3106 host.config = strdup (filename);
3107}
3108
3109void
3110install_default (enum node_type node)
3111{
3112 install_element (node, &config_exit_cmd);
3113 install_element (node, &config_quit_cmd);
3114 install_element (node, &config_end_cmd);
3115 install_element (node, &config_help_cmd);
3116 install_element (node, &config_list_cmd);
3117
3118 install_element (node, &config_write_terminal_cmd);
3119 install_element (node, &config_write_file_cmd);
3120 install_element (node, &config_write_memory_cmd);
3121 install_element (node, &config_write_cmd);
3122 install_element (node, &show_running_config_cmd);
3123}
3124
3125/* Initialize command interface. Install basic nodes and commands. */
3126void
3127cmd_init (int terminal)
3128{
3129 /* Allocate initial top vector of commands. */
3130 cmdvec = vector_init (VECTOR_MIN_SIZE);
3131
3132 /* Default host value settings. */
3133 host.name = NULL;
3134 host.password = NULL;
3135 host.enable = NULL;
3136 host.logfile = NULL;
3137 host.config = NULL;
3138 host.lines = -1;
3139 host.motd = default_motd;
3140
3141 /* Install top nodes. */
3142 install_node (&view_node, NULL);
3143 install_node (&enable_node, NULL);
3144 install_node (&auth_node, NULL);
3145 install_node (&auth_enable_node, NULL);
3146 install_node (&config_node, config_write_host);
3147
3148 /* Each node's basic commands. */
3149 install_element (VIEW_NODE, &show_version_cmd);
3150 if (terminal)
3151 {
3152 install_element (VIEW_NODE, &config_list_cmd);
3153 install_element (VIEW_NODE, &config_exit_cmd);
3154 install_element (VIEW_NODE, &config_quit_cmd);
3155 install_element (VIEW_NODE, &config_help_cmd);
3156 install_element (VIEW_NODE, &config_enable_cmd);
3157 install_element (VIEW_NODE, &config_terminal_length_cmd);
3158 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3159 }
3160
3161 if (terminal)
3162 {
3163 install_default (ENABLE_NODE);
3164 install_element (ENABLE_NODE, &config_disable_cmd);
3165 install_element (ENABLE_NODE, &config_terminal_cmd);
3166 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3167 }
3168 install_element (ENABLE_NODE, &show_startup_config_cmd);
3169 install_element (ENABLE_NODE, &show_version_cmd);
3170 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3171 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3172
3173 if (terminal)
3174 install_default (CONFIG_NODE);
3175 install_element (CONFIG_NODE, &hostname_cmd);
3176 install_element (CONFIG_NODE, &no_hostname_cmd);
3177 install_element (CONFIG_NODE, &password_cmd);
3178 install_element (CONFIG_NODE, &password_text_cmd);
3179 install_element (CONFIG_NODE, &enable_password_cmd);
3180 install_element (CONFIG_NODE, &enable_password_text_cmd);
3181 install_element (CONFIG_NODE, &no_enable_password_cmd);
3182 if (terminal)
3183 {
3184 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3185 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3186 install_element (CONFIG_NODE, &config_log_file_cmd);
3187 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3188 install_element (CONFIG_NODE, &config_log_syslog_cmd);
3189 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
3190 install_element (CONFIG_NODE, &config_log_trap_cmd);
3191 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3192 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3193 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3194 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3195 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3196 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3197 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3198 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3199 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3200 }
3201
3202 srand(time(NULL));
3203}