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