blob: 5d429338e473686c8b0a1160dd116031691a89d2 [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;
hasso726f9b22003-05-25 21:04:54 +0000721 struct sockaddr_in6 sin6_dummy;
722 int ret;
paul718e3742002-12-13 20:15:29 +0000723
724 if (str == NULL)
725 return partly_match;
726
727 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
728 return no_match;
729
hasso726f9b22003-05-25 21:04:54 +0000730 /* use inet_pton that has a better support,
731 * for example inet_pton can support the automatic addresses:
732 * ::1.2.3.4
733 */
734 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
735
736 if (ret == 1)
737 return exact_match;
738
paul718e3742002-12-13 20:15:29 +0000739 while (*str != '\0')
740 {
741 switch (state)
742 {
743 case STATE_START:
744 if (*str == ':')
745 {
746 if (*(str + 1) != ':' && *(str + 1) != '\0')
747 return no_match;
748 colons--;
749 state = STATE_COLON;
750 }
751 else
752 {
753 sp = str;
754 state = STATE_ADDR;
755 }
756
757 continue;
758 case STATE_COLON:
759 colons++;
760 if (*(str + 1) == ':')
761 state = STATE_DOUBLE;
762 else
763 {
764 sp = str + 1;
765 state = STATE_ADDR;
766 }
767 break;
768 case STATE_DOUBLE:
769 if (double_colon)
770 return no_match;
771
772 if (*(str + 1) == ':')
773 return no_match;
774 else
775 {
776 if (*(str + 1) != '\0')
777 colons++;
778 sp = str + 1;
779 state = STATE_ADDR;
780 }
781
782 double_colon++;
783 nums++;
784 break;
785 case STATE_ADDR:
786 if (*(str + 1) == ':' || *(str + 1) == '\0')
787 {
788 if (str - sp > 3)
789 return no_match;
790
791 nums++;
792 state = STATE_COLON;
793 }
794 if (*(str + 1) == '.')
795 state = STATE_DOT;
796 break;
797 case STATE_DOT:
798 state = STATE_ADDR;
799 break;
800 default:
801 break;
802 }
803
804 if (nums > 8)
805 return no_match;
806
807 if (colons > 7)
808 return no_match;
809
810 str++;
811 }
812
813#if 0
814 if (nums < 11)
815 return partly_match;
816#endif /* 0 */
817
818 return exact_match;
819}
820
821enum match_type
822cmd_ipv6_prefix_match (char *str)
823{
824 int state = STATE_START;
825 int colons = 0, nums = 0, double_colon = 0;
826 int mask;
827 char *sp = NULL;
828 char *endptr = NULL;
829
830 if (str == NULL)
831 return partly_match;
832
833 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
834 return no_match;
835
836 while (*str != '\0' && state != STATE_MASK)
837 {
838 switch (state)
839 {
840 case STATE_START:
841 if (*str == ':')
842 {
843 if (*(str + 1) != ':' && *(str + 1) != '\0')
844 return no_match;
845 colons--;
846 state = STATE_COLON;
847 }
848 else
849 {
850 sp = str;
851 state = STATE_ADDR;
852 }
853
854 continue;
855 case STATE_COLON:
856 colons++;
857 if (*(str + 1) == '/')
858 return no_match;
859 else if (*(str + 1) == ':')
860 state = STATE_DOUBLE;
861 else
862 {
863 sp = str + 1;
864 state = STATE_ADDR;
865 }
866 break;
867 case STATE_DOUBLE:
868 if (double_colon)
869 return no_match;
870
871 if (*(str + 1) == ':')
872 return no_match;
873 else
874 {
875 if (*(str + 1) != '\0' && *(str + 1) != '/')
876 colons++;
877 sp = str + 1;
878
879 if (*(str + 1) == '/')
880 state = STATE_SLASH;
881 else
882 state = STATE_ADDR;
883 }
884
885 double_colon++;
886 nums += 1;
887 break;
888 case STATE_ADDR:
889 if (*(str + 1) == ':' || *(str + 1) == '.'
890 || *(str + 1) == '\0' || *(str + 1) == '/')
891 {
892 if (str - sp > 3)
893 return no_match;
894
895 for (; sp <= str; sp++)
896 if (*sp == '/')
897 return no_match;
898
899 nums++;
900
901 if (*(str + 1) == ':')
902 state = STATE_COLON;
903 else if (*(str + 1) == '.')
904 state = STATE_DOT;
905 else if (*(str + 1) == '/')
906 state = STATE_SLASH;
907 }
908 break;
909 case STATE_DOT:
910 state = STATE_ADDR;
911 break;
912 case STATE_SLASH:
913 if (*(str + 1) == '\0')
914 return partly_match;
915
916 state = STATE_MASK;
917 break;
918 default:
919 break;
920 }
921
922 if (nums > 11)
923 return no_match;
924
925 if (colons > 7)
926 return no_match;
927
928 str++;
929 }
930
931 if (state < STATE_MASK)
932 return partly_match;
933
934 mask = strtol (str, &endptr, 10);
935 if (*endptr != '\0')
936 return no_match;
937
938 if (mask < 0 || mask > 128)
939 return no_match;
940
941/* I don't know why mask < 13 makes command match partly.
942 Forgive me to make this comments. I Want to set static default route
943 because of lack of function to originate default in ospf6d; sorry
944 yasu
945 if (mask < 13)
946 return partly_match;
947*/
948
949 return exact_match;
950}
951
952#define DECIMAL_STRLEN_MAX 10
953
954int
955cmd_range_match (char *range, char *str)
956{
957 char *p;
958 char buf[DECIMAL_STRLEN_MAX + 1];
959 char *endptr = NULL;
960 unsigned long min, max, val;
961
962 if (str == NULL)
963 return 1;
964
965 val = strtoul (str, &endptr, 10);
966 if (*endptr != '\0')
967 return 0;
968
969 range++;
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 min = strtoul (buf, &endptr, 10);
978 if (*endptr != '\0')
979 return 0;
980
981 range = p + 1;
982 p = strchr (range, '>');
983 if (p == NULL)
984 return 0;
985 if (p - range > DECIMAL_STRLEN_MAX)
986 return 0;
987 strncpy (buf, range, p - range);
988 buf[p - range] = '\0';
989 max = strtoul (buf, &endptr, 10);
990 if (*endptr != '\0')
991 return 0;
992
993 if (val < min || val > max)
994 return 0;
995
996 return 1;
997}
998
999/* Make completion match and return match type flag. */
1000enum match_type
1001cmd_filter_by_completion (char *command, vector v, int index)
1002{
1003 int i;
1004 char *str;
1005 struct cmd_element *cmd_element;
1006 enum match_type match_type;
1007 vector descvec;
1008 struct desc *desc;
1009
1010 match_type = no_match;
1011
1012 /* If command and cmd_element string does not match set NULL to vector */
1013 for (i = 0; i < vector_max (v); i++)
1014 if ((cmd_element = vector_slot (v, i)) != NULL)
1015 {
1016 if (index >= vector_max (cmd_element->strvec))
1017 vector_slot (v, i) = NULL;
1018 else
1019 {
1020 int j;
1021 int matched = 0;
1022
1023 descvec = vector_slot (cmd_element->strvec, index);
1024
1025 for (j = 0; j < vector_max (descvec); j++)
1026 {
1027 desc = vector_slot (descvec, j);
1028 str = desc->cmd;
1029
1030 if (CMD_VARARG (str))
1031 {
1032 if (match_type < vararg_match)
1033 match_type = vararg_match;
1034 matched++;
1035 }
1036 else if (CMD_RANGE (str))
1037 {
1038 if (cmd_range_match (str, command))
1039 {
1040 if (match_type < range_match)
1041 match_type = range_match;
1042
1043 matched++;
1044 }
1045 }
1046 else if (CMD_IPV6 (str))
1047 {
1048 if (cmd_ipv6_match (command))
1049 {
1050 if (match_type < ipv6_match)
1051 match_type = ipv6_match;
1052
1053 matched++;
1054 }
1055 }
1056 else if (CMD_IPV6_PREFIX (str))
1057 {
1058 if (cmd_ipv6_prefix_match (command))
1059 {
1060 if (match_type < ipv6_prefix_match)
1061 match_type = ipv6_prefix_match;
1062
1063 matched++;
1064 }
1065 }
1066 else if (CMD_IPV4 (str))
1067 {
1068 if (cmd_ipv4_match (command))
1069 {
1070 if (match_type < ipv4_match)
1071 match_type = ipv4_match;
1072
1073 matched++;
1074 }
1075 }
1076 else if (CMD_IPV4_PREFIX (str))
1077 {
1078 if (cmd_ipv4_prefix_match (command))
1079 {
1080 if (match_type < ipv4_prefix_match)
1081 match_type = ipv4_prefix_match;
1082 matched++;
1083 }
1084 }
1085 else
1086 /* Check is this point's argument optional ? */
1087 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1088 {
1089 if (match_type < extend_match)
1090 match_type = extend_match;
1091 matched++;
1092 }
1093 else if (strncmp (command, str, strlen (command)) == 0)
1094 {
1095 if (strcmp (command, str) == 0)
1096 match_type = exact_match;
1097 else
1098 {
1099 if (match_type < partly_match)
1100 match_type = partly_match;
1101 }
1102 matched++;
1103 }
1104 }
1105 if (! matched)
1106 vector_slot (v, i) = NULL;
1107 }
1108 }
1109 return match_type;
1110}
1111
1112/* Filter vector by command character with index. */
1113enum match_type
1114cmd_filter_by_string (char *command, vector v, int index)
1115{
1116 int i;
1117 char *str;
1118 struct cmd_element *cmd_element;
1119 enum match_type match_type;
1120 vector descvec;
1121 struct desc *desc;
1122
1123 match_type = no_match;
1124
1125 /* If command and cmd_element string does not match set NULL to vector */
1126 for (i = 0; i < vector_max (v); i++)
1127 if ((cmd_element = vector_slot (v, i)) != NULL)
1128 {
1129 /* If given index is bigger than max string vector of command,
1130 set NULL*/
1131 if (index >= vector_max (cmd_element->strvec))
1132 vector_slot (v, i) = NULL;
1133 else
1134 {
1135 int j;
1136 int matched = 0;
1137
1138 descvec = vector_slot (cmd_element->strvec, index);
1139
1140 for (j = 0; j < vector_max (descvec); j++)
1141 {
1142 desc = vector_slot (descvec, j);
1143 str = desc->cmd;
1144
1145 if (CMD_VARARG (str))
1146 {
1147 if (match_type < vararg_match)
1148 match_type = vararg_match;
1149 matched++;
1150 }
1151 else if (CMD_RANGE (str))
1152 {
1153 if (cmd_range_match (str, command))
1154 {
1155 if (match_type < range_match)
1156 match_type = range_match;
1157 matched++;
1158 }
1159 }
1160 else if (CMD_IPV6 (str))
1161 {
1162 if (cmd_ipv6_match (command) == exact_match)
1163 {
1164 if (match_type < ipv6_match)
1165 match_type = ipv6_match;
1166 matched++;
1167 }
1168 }
1169 else if (CMD_IPV6_PREFIX (str))
1170 {
1171 if (cmd_ipv6_prefix_match (command) == exact_match)
1172 {
1173 if (match_type < ipv6_prefix_match)
1174 match_type = ipv6_prefix_match;
1175 matched++;
1176 }
1177 }
1178 else if (CMD_IPV4 (str))
1179 {
1180 if (cmd_ipv4_match (command) == exact_match)
1181 {
1182 if (match_type < ipv4_match)
1183 match_type = ipv4_match;
1184 matched++;
1185 }
1186 }
1187 else if (CMD_IPV4_PREFIX (str))
1188 {
1189 if (cmd_ipv4_prefix_match (command) == exact_match)
1190 {
1191 if (match_type < ipv4_prefix_match)
1192 match_type = ipv4_prefix_match;
1193 matched++;
1194 }
1195 }
1196 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1197 {
1198 if (match_type < extend_match)
1199 match_type = extend_match;
1200 matched++;
1201 }
1202 else
1203 {
1204 if (strcmp (command, str) == 0)
1205 {
1206 match_type = exact_match;
1207 matched++;
1208 }
1209 }
1210 }
1211 if (! matched)
1212 vector_slot (v, i) = NULL;
1213 }
1214 }
1215 return match_type;
1216}
1217
1218/* Check ambiguous match */
1219int
1220is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1221{
1222 int i;
1223 int j;
1224 char *str = NULL;
1225 struct cmd_element *cmd_element;
1226 char *matched = NULL;
1227 vector descvec;
1228 struct desc *desc;
1229
1230 for (i = 0; i < vector_max (v); i++)
1231 if ((cmd_element = vector_slot (v, i)) != NULL)
1232 {
1233 int match = 0;
1234
1235 descvec = vector_slot (cmd_element->strvec, index);
1236
1237 for (j = 0; j < vector_max (descvec); j++)
1238 {
1239 enum match_type ret;
1240
1241 desc = vector_slot (descvec, j);
1242 str = desc->cmd;
1243
1244 switch (type)
1245 {
1246 case exact_match:
1247 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1248 && strcmp (command, str) == 0)
1249 match++;
1250 break;
1251 case partly_match:
1252 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1253 && strncmp (command, str, strlen (command)) == 0)
1254 {
1255 if (matched && strcmp (matched, str) != 0)
1256 return 1; /* There is ambiguous match. */
1257 else
1258 matched = str;
1259 match++;
1260 }
1261 break;
1262 case range_match:
1263 if (cmd_range_match (str, command))
1264 {
1265 if (matched && strcmp (matched, str) != 0)
1266 return 1;
1267 else
1268 matched = str;
1269 match++;
1270 }
1271 break;
1272 case ipv6_match:
1273 if (CMD_IPV6 (str))
1274 match++;
1275 break;
1276 case ipv6_prefix_match:
1277 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1278 {
1279 if (ret == partly_match)
1280 return 2; /* There is incomplete match. */
1281
1282 match++;
1283 }
1284 break;
1285 case ipv4_match:
1286 if (CMD_IPV4 (str))
1287 match++;
1288 break;
1289 case ipv4_prefix_match:
1290 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1291 {
1292 if (ret == partly_match)
1293 return 2; /* There is incomplete match. */
1294
1295 match++;
1296 }
1297 break;
1298 case extend_match:
1299 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1300 match++;
1301 break;
1302 case no_match:
1303 default:
1304 break;
1305 }
1306 }
1307 if (! match)
1308 vector_slot (v, i) = NULL;
1309 }
1310 return 0;
1311}
1312
1313/* If src matches dst return dst string, otherwise return NULL */
1314char *
1315cmd_entry_function (char *src, char *dst)
1316{
1317 /* Skip variable arguments. */
1318 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1319 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1320 return NULL;
1321
1322 /* In case of 'command \t', given src is NULL string. */
1323 if (src == NULL)
1324 return dst;
1325
1326 /* Matched with input string. */
1327 if (strncmp (src, dst, strlen (src)) == 0)
1328 return dst;
1329
1330 return NULL;
1331}
1332
1333/* If src matches dst return dst string, otherwise return NULL */
1334/* This version will return the dst string always if it is
1335 CMD_VARIABLE for '?' key processing */
1336char *
1337cmd_entry_function_desc (char *src, char *dst)
1338{
1339 if (CMD_VARARG (dst))
1340 return dst;
1341
1342 if (CMD_RANGE (dst))
1343 {
1344 if (cmd_range_match (dst, src))
1345 return dst;
1346 else
1347 return NULL;
1348 }
1349
1350 if (CMD_IPV6 (dst))
1351 {
1352 if (cmd_ipv6_match (src))
1353 return dst;
1354 else
1355 return NULL;
1356 }
1357
1358 if (CMD_IPV6_PREFIX (dst))
1359 {
1360 if (cmd_ipv6_prefix_match (src))
1361 return dst;
1362 else
1363 return NULL;
1364 }
1365
1366 if (CMD_IPV4 (dst))
1367 {
1368 if (cmd_ipv4_match (src))
1369 return dst;
1370 else
1371 return NULL;
1372 }
1373
1374 if (CMD_IPV4_PREFIX (dst))
1375 {
1376 if (cmd_ipv4_prefix_match (src))
1377 return dst;
1378 else
1379 return NULL;
1380 }
1381
1382 /* Optional or variable commands always match on '?' */
1383 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1384 return dst;
1385
1386 /* In case of 'command \t', given src is NULL string. */
1387 if (src == NULL)
1388 return dst;
1389
1390 if (strncmp (src, dst, strlen (src)) == 0)
1391 return dst;
1392 else
1393 return NULL;
1394}
1395
1396/* Check same string element existence. If it isn't there return
1397 1. */
1398int
1399cmd_unique_string (vector v, char *str)
1400{
1401 int i;
1402 char *match;
1403
1404 for (i = 0; i < vector_max (v); i++)
1405 if ((match = vector_slot (v, i)) != NULL)
1406 if (strcmp (match, str) == 0)
1407 return 0;
1408 return 1;
1409}
1410
1411/* Compare string to description vector. If there is same string
1412 return 1 else return 0. */
1413int
1414desc_unique_string (vector v, char *str)
1415{
1416 int i;
1417 struct desc *desc;
1418
1419 for (i = 0; i < vector_max (v); i++)
1420 if ((desc = vector_slot (v, i)) != NULL)
1421 if (strcmp (desc->cmd, str) == 0)
1422 return 1;
1423 return 0;
1424}
1425
paulb92938a2002-12-13 21:20:42 +00001426int
1427cmd_try_do_shortcut (enum node_type node, char* first_word) {
1428 if ( first_word != NULL &&
1429 node != AUTH_NODE &&
1430 node != VIEW_NODE &&
1431 node != AUTH_ENABLE_NODE &&
1432 node != ENABLE_NODE &&
1433 0 == strcmp( "do", first_word ) )
1434 return 1;
1435 return 0;
1436}
1437
paul718e3742002-12-13 20:15:29 +00001438/* '?' describe command support. */
1439vector
paulb92938a2002-12-13 21:20:42 +00001440cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001441{
1442 int i;
1443 vector cmd_vector;
1444#define INIT_MATCHVEC_SIZE 10
1445 vector matchvec;
1446 struct cmd_element *cmd_element;
1447 int index;
1448 static struct desc desc_cr = { "<cr>", "" };
1449
1450 /* Set index. */
1451 index = vector_max (vline) - 1;
1452
1453 /* Make copy vector of current node's command vector. */
1454 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1455
1456 /* Prepare match vector */
1457 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1458
1459 /* Filter commands. */
1460 for (i = 0; i < index; i++)
1461 {
1462 enum match_type match;
1463 char *command;
1464 int ret;
1465
1466 command = vector_slot (vline, i);
1467
1468 match = cmd_filter_by_completion (command, cmd_vector, i);
1469
1470 if (match == vararg_match)
1471 {
1472 struct cmd_element *cmd_element;
1473 vector descvec;
1474 int j, k;
1475
1476 for (j = 0; j < vector_max (cmd_vector); j++)
1477 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1478 {
1479 descvec = vector_slot (cmd_element->strvec,
1480 vector_max (cmd_element->strvec) - 1);
1481 for (k = 0; k < vector_max (descvec); k++)
1482 {
1483 struct desc *desc = vector_slot (descvec, k);
1484 vector_set (matchvec, desc);
1485 }
1486 }
1487
1488 vector_set (matchvec, &desc_cr);
1489
1490 vector_free (cmd_vector);
1491
1492 return matchvec;
1493 }
1494
1495 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1496 {
1497 vector_free (cmd_vector);
1498 *status = CMD_ERR_AMBIGUOUS;
1499 return NULL;
1500 }
1501 else if (ret == 2)
1502 {
1503 vector_free (cmd_vector);
1504 *status = CMD_ERR_NO_MATCH;
1505 return NULL;
1506 }
1507 }
1508
1509 /* Prepare match vector */
1510 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1511
1512 /* Make description vector. */
1513 for (i = 0; i < vector_max (cmd_vector); i++)
1514 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1515 {
1516 char *string = NULL;
1517 vector strvec = cmd_element->strvec;
1518
1519 if (index > vector_max (strvec))
1520 vector_slot (cmd_vector, i) = NULL;
1521 else
1522 {
1523 /* Check is command is completed. */
1524 if (index == vector_max (strvec))
1525 {
1526 string = "<cr>";
1527 if (! desc_unique_string (matchvec, string))
1528 vector_set (matchvec, &desc_cr);
1529 }
1530 else
1531 {
1532 int j;
1533 vector descvec = vector_slot (strvec, index);
1534 struct desc *desc;
1535
1536 for (j = 0; j < vector_max (descvec); j++)
1537 {
1538 desc = vector_slot (descvec, j);
1539 string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
1540 if (string)
1541 {
1542 /* Uniqueness check */
1543 if (! desc_unique_string (matchvec, string))
1544 vector_set (matchvec, desc);
1545 }
1546 }
1547 }
1548 }
1549 }
1550 vector_free (cmd_vector);
1551
1552 if (vector_slot (matchvec, 0) == NULL)
1553 {
1554 vector_free (matchvec);
1555 *status= CMD_ERR_NO_MATCH;
1556 }
1557 else
1558 *status = CMD_SUCCESS;
1559
1560 return matchvec;
1561}
1562
paulb92938a2002-12-13 21:20:42 +00001563vector
1564cmd_describe_command (vector vline, struct vty *vty, int *status)
1565{
1566 vector ret;
1567
1568 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1569 {
1570 enum node_type onode;
1571 vector shifted_vline;
1572 int index;
1573
1574 onode = vty->node;
1575 vty->node = ENABLE_NODE;
1576 /* We can try it on enable node, cos' the vty is authenticated */
1577
1578 shifted_vline = vector_init (vector_count(vline));
1579 /* use memcpy? */
1580 for (index = 1; index < vector_max (vline); index++)
1581 {
1582 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1583 }
1584
1585 ret = cmd_describe_command_real (shifted_vline, vty, status);
1586
1587 vector_free(shifted_vline);
1588 vty->node = onode;
1589 return ret;
1590 }
1591
1592
1593 return cmd_describe_command_real (vline, vty, status);
1594}
1595
1596
paul718e3742002-12-13 20:15:29 +00001597/* Check LCD of matched command. */
1598int
1599cmd_lcd (char **matched)
1600{
1601 int i;
1602 int j;
1603 int lcd = -1;
1604 char *s1, *s2;
1605 char c1, c2;
1606
1607 if (matched[0] == NULL || matched[1] == NULL)
1608 return 0;
1609
1610 for (i = 1; matched[i] != NULL; i++)
1611 {
1612 s1 = matched[i - 1];
1613 s2 = matched[i];
1614
1615 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1616 if (c1 != c2)
1617 break;
1618
1619 if (lcd < 0)
1620 lcd = j;
1621 else
1622 {
1623 if (lcd > j)
1624 lcd = j;
1625 }
1626 }
1627 return lcd;
1628}
1629
1630/* Command line completion support. */
1631char **
paulb92938a2002-12-13 21:20:42 +00001632cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001633{
1634 int i;
1635 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1636#define INIT_MATCHVEC_SIZE 10
1637 vector matchvec;
1638 struct cmd_element *cmd_element;
1639 int index = vector_max (vline) - 1;
1640 char **match_str;
1641 struct desc *desc;
1642 vector descvec;
1643 char *command;
1644 int lcd;
1645
1646 /* First, filter by preceeding command string */
1647 for (i = 0; i < index; i++)
1648 {
1649 enum match_type match;
1650 int ret;
1651
1652 command = vector_slot (vline, i);
1653
1654 /* First try completion match, if there is exactly match return 1 */
1655 match = cmd_filter_by_completion (command, cmd_vector, i);
1656
1657 /* If there is exact match then filter ambiguous match else check
1658 ambiguousness. */
1659 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1660 {
1661 vector_free (cmd_vector);
1662 *status = CMD_ERR_AMBIGUOUS;
1663 return NULL;
1664 }
1665 /*
1666 else if (ret == 2)
1667 {
1668 vector_free (cmd_vector);
1669 *status = CMD_ERR_NO_MATCH;
1670 return NULL;
1671 }
1672 */
1673 }
1674
1675 /* Prepare match vector. */
1676 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1677
1678 /* Now we got into completion */
1679 for (i = 0; i < vector_max (cmd_vector); i++)
1680 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1681 {
1682 char *string;
1683 vector strvec = cmd_element->strvec;
1684
1685 /* Check field length */
1686 if (index >= vector_max (strvec))
1687 vector_slot (cmd_vector, i) = NULL;
1688 else
1689 {
1690 int j;
1691
1692 descvec = vector_slot (strvec, index);
1693 for (j = 0; j < vector_max (descvec); j++)
1694 {
1695 desc = vector_slot (descvec, j);
1696
1697 if ((string = cmd_entry_function (vector_slot (vline, index),
1698 desc->cmd)))
1699 if (cmd_unique_string (matchvec, string))
1700 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1701 }
1702 }
1703 }
1704
1705 /* We don't need cmd_vector any more. */
1706 vector_free (cmd_vector);
1707
1708 /* No matched command */
1709 if (vector_slot (matchvec, 0) == NULL)
1710 {
1711 vector_free (matchvec);
1712
1713 /* In case of 'command \t' pattern. Do you need '?' command at
1714 the end of the line. */
1715 if (vector_slot (vline, index) == '\0')
1716 *status = CMD_ERR_NOTHING_TODO;
1717 else
1718 *status = CMD_ERR_NO_MATCH;
1719 return NULL;
1720 }
1721
1722 /* Only one matched */
1723 if (vector_slot (matchvec, 1) == NULL)
1724 {
1725 match_str = (char **) matchvec->index;
1726 vector_only_wrapper_free (matchvec);
1727 *status = CMD_COMPLETE_FULL_MATCH;
1728 return match_str;
1729 }
1730 /* Make it sure last element is NULL. */
1731 vector_set (matchvec, NULL);
1732
1733 /* Check LCD of matched strings. */
1734 if (vector_slot (vline, index) != NULL)
1735 {
1736 lcd = cmd_lcd ((char **) matchvec->index);
1737
1738 if (lcd)
1739 {
1740 int len = strlen (vector_slot (vline, index));
1741
1742 if (len < lcd)
1743 {
1744 char *lcdstr;
1745
1746 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1747 memcpy (lcdstr, matchvec->index[0], lcd);
1748 lcdstr[lcd] = '\0';
1749
1750 /* match_str = (char **) &lcdstr; */
1751
1752 /* Free matchvec. */
1753 for (i = 0; i < vector_max (matchvec); i++)
1754 {
1755 if (vector_slot (matchvec, i))
1756 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1757 }
1758 vector_free (matchvec);
1759
1760 /* Make new matchvec. */
1761 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1762 vector_set (matchvec, lcdstr);
1763 match_str = (char **) matchvec->index;
1764 vector_only_wrapper_free (matchvec);
1765
1766 *status = CMD_COMPLETE_MATCH;
1767 return match_str;
1768 }
1769 }
1770 }
1771
1772 match_str = (char **) matchvec->index;
1773 vector_only_wrapper_free (matchvec);
1774 *status = CMD_COMPLETE_LIST_MATCH;
1775 return match_str;
1776}
1777
paulb92938a2002-12-13 21:20:42 +00001778char **
paul9ab68122003-01-18 01:16:20 +00001779cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001780{
1781 char **ret;
1782
1783 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1784 {
1785 enum node_type onode;
1786 vector shifted_vline;
1787 int index;
1788
1789 onode = vty->node;
1790 vty->node = ENABLE_NODE;
1791 /* We can try it on enable node, cos' the vty is authenticated */
1792
1793 shifted_vline = vector_init (vector_count(vline));
1794 /* use memcpy? */
1795 for (index = 1; index < vector_max (vline); index++)
1796 {
1797 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1798 }
1799
1800 ret = cmd_complete_command_real (shifted_vline, vty, status);
1801
1802 vector_free(shifted_vline);
1803 vty->node = onode;
1804 return ret;
1805 }
1806
1807
1808 return cmd_complete_command_real (vline, vty, status);
1809}
1810
1811/* return parent node */
1812/* MUST eventually converge on CONFIG_NODE */
1813enum node_type node_parent ( enum node_type node )
1814{
1815 enum node_type ret;
1816
paul9ab68122003-01-18 01:16:20 +00001817 assert (node > CONFIG_NODE);
1818
1819 switch (node)
1820 {
1821 case BGP_VPNV4_NODE:
1822 case BGP_IPV4_NODE:
1823 case BGP_IPV4M_NODE:
1824 case BGP_IPV6_NODE:
1825 ret = BGP_NODE;
1826 break;
1827 case KEYCHAIN_KEY_NODE:
1828 ret = KEYCHAIN_NODE;
1829 break;
1830 default:
1831 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001832 }
1833
1834 return ret;
1835}
1836
paul718e3742002-12-13 20:15:29 +00001837/* Execute command by argument vline vector. */
1838int
paulb92938a2002-12-13 21:20:42 +00001839cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001840{
1841 int i;
1842 int index;
1843 vector cmd_vector;
1844 struct cmd_element *cmd_element;
1845 struct cmd_element *matched_element;
1846 unsigned int matched_count, incomplete_count;
1847 int argc;
1848 char *argv[CMD_ARGC_MAX];
1849 enum match_type match = 0;
1850 int varflag;
1851 char *command;
1852
1853 /* Make copy of command elements. */
1854 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1855
1856 for (index = 0; index < vector_max (vline); index++)
1857 {
1858 int ret;
1859
1860 command = vector_slot (vline, index);
1861
1862 match = cmd_filter_by_completion (command, cmd_vector, index);
1863
1864 if (match == vararg_match)
1865 break;
1866
1867 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1868
1869 if (ret == 1)
1870 {
1871 vector_free (cmd_vector);
1872 return CMD_ERR_AMBIGUOUS;
1873 }
1874 else if (ret == 2)
1875 {
1876 vector_free (cmd_vector);
1877 return CMD_ERR_NO_MATCH;
1878 }
1879 }
1880
1881 /* Check matched count. */
1882 matched_element = NULL;
1883 matched_count = 0;
1884 incomplete_count = 0;
1885
1886 for (i = 0; i < vector_max (cmd_vector); i++)
1887 if (vector_slot (cmd_vector,i) != NULL)
1888 {
1889 cmd_element = vector_slot (cmd_vector,i);
1890
1891 if (match == vararg_match || index >= cmd_element->cmdsize)
1892 {
1893 matched_element = cmd_element;
1894#if 0
1895 printf ("DEBUG: %s\n", cmd_element->string);
1896#endif
1897 matched_count++;
1898 }
1899 else
1900 {
1901 incomplete_count++;
1902 }
1903 }
1904
1905 /* Finish of using cmd_vector. */
1906 vector_free (cmd_vector);
1907
1908 /* To execute command, matched_count must be 1.*/
1909 if (matched_count == 0)
1910 {
1911 if (incomplete_count)
1912 return CMD_ERR_INCOMPLETE;
1913 else
1914 return CMD_ERR_NO_MATCH;
1915 }
1916
1917 if (matched_count > 1)
1918 return CMD_ERR_AMBIGUOUS;
1919
1920 /* Argument treatment */
1921 varflag = 0;
1922 argc = 0;
1923
1924 for (i = 0; i < vector_max (vline); i++)
1925 {
1926 if (varflag)
1927 argv[argc++] = vector_slot (vline, i);
1928 else
1929 {
1930 vector descvec = vector_slot (matched_element->strvec, i);
1931
1932 if (vector_max (descvec) == 1)
1933 {
1934 struct desc *desc = vector_slot (descvec, 0);
1935 char *str = desc->cmd;
1936
1937 if (CMD_VARARG (str))
1938 varflag = 1;
1939
1940 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
1941 argv[argc++] = vector_slot (vline, i);
1942 }
1943 else
1944 argv[argc++] = vector_slot (vline, i);
1945 }
1946
1947 if (argc >= CMD_ARGC_MAX)
1948 return CMD_ERR_EXEED_ARGC_MAX;
1949 }
1950
1951 /* For vtysh execution. */
1952 if (cmd)
1953 *cmd = matched_element;
1954
1955 if (matched_element->daemon)
1956 return CMD_SUCCESS_DAEMON;
1957
1958 /* Execute matched command. */
1959 return (*matched_element->func) (matched_element, vty, argc, argv);
1960}
1961
paulb92938a2002-12-13 21:20:42 +00001962
1963int
1964cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
paul9ab68122003-01-18 01:16:20 +00001965 int ret, saved_ret, tried = 0;
1966 enum node_type onode, try_node;
1967
1968 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00001969
1970 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1971 {
1972 vector shifted_vline;
1973 int index;
1974
1975 vty->node = ENABLE_NODE;
1976 /* We can try it on enable node, cos' the vty is authenticated */
1977
1978 shifted_vline = vector_init (vector_count(vline));
1979 /* use memcpy? */
1980 for (index = 1; index < vector_max (vline); index++)
1981 {
1982 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1983 }
1984
1985 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
1986
1987 vector_free(shifted_vline);
1988 vty->node = onode;
1989 return ret;
1990 }
1991
1992
paul9ab68122003-01-18 01:16:20 +00001993 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00001994
1995 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00001996 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00001997 && vty->node > CONFIG_NODE )
1998 {
paul9ab68122003-01-18 01:16:20 +00001999 try_node = node_parent(try_node);
2000 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002001 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002002 tried = 1;
2003 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002004 {
paul9ab68122003-01-18 01:16:20 +00002005 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002006 return ret;
2007 }
paulb92938a2002-12-13 21:20:42 +00002008 }
paul9ab68122003-01-18 01:16:20 +00002009 /* no command succeeded, reset the vty to the original node and
2010 return the error for this node */
2011 if ( tried )
2012 vty->node = onode;
2013 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002014}
2015
paul718e3742002-12-13 20:15:29 +00002016/* Execute command by argument readline. */
2017int
2018cmd_execute_command_strict (vector vline, struct vty *vty,
2019 struct cmd_element **cmd)
2020{
2021 int i;
2022 int index;
2023 vector cmd_vector;
2024 struct cmd_element *cmd_element;
2025 struct cmd_element *matched_element;
2026 unsigned int matched_count, incomplete_count;
2027 int argc;
2028 char *argv[CMD_ARGC_MAX];
2029 int varflag;
2030 enum match_type match = 0;
2031 char *command;
2032
2033 /* Make copy of command element */
2034 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2035
2036 for (index = 0; index < vector_max (vline); index++)
2037 {
2038 int ret;
2039
2040 command = vector_slot (vline, index);
2041
2042 match = cmd_filter_by_string (vector_slot (vline, index),
2043 cmd_vector, index);
2044
2045 /* If command meets '.VARARG' then finish matching. */
2046 if (match == vararg_match)
2047 break;
2048
2049 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2050 if (ret == 1)
2051 {
2052 vector_free (cmd_vector);
2053 return CMD_ERR_AMBIGUOUS;
2054 }
2055 if (ret == 2)
2056 {
2057 vector_free (cmd_vector);
2058 return CMD_ERR_NO_MATCH;
2059 }
2060 }
2061
2062 /* Check matched count. */
2063 matched_element = NULL;
2064 matched_count = 0;
2065 incomplete_count = 0;
2066 for (i = 0; i < vector_max (cmd_vector); i++)
2067 if (vector_slot (cmd_vector,i) != NULL)
2068 {
2069 cmd_element = vector_slot (cmd_vector,i);
2070
2071 if (match == vararg_match || index >= cmd_element->cmdsize)
2072 {
2073 matched_element = cmd_element;
2074 matched_count++;
2075 }
2076 else
2077 incomplete_count++;
2078 }
2079
2080 /* Finish of using cmd_vector. */
2081 vector_free (cmd_vector);
2082
2083 /* To execute command, matched_count must be 1.*/
2084 if (matched_count == 0)
2085 {
2086 if (incomplete_count)
2087 return CMD_ERR_INCOMPLETE;
2088 else
2089 return CMD_ERR_NO_MATCH;
2090 }
2091
2092 if (matched_count > 1)
2093 return CMD_ERR_AMBIGUOUS;
2094
2095 /* Argument treatment */
2096 varflag = 0;
2097 argc = 0;
2098
2099 for (i = 0; i < vector_max (vline); i++)
2100 {
2101 if (varflag)
2102 argv[argc++] = vector_slot (vline, i);
2103 else
2104 {
2105 vector descvec = vector_slot (matched_element->strvec, i);
2106
2107 if (vector_max (descvec) == 1)
2108 {
2109 struct desc *desc = vector_slot (descvec, 0);
2110 char *str = desc->cmd;
2111
2112 if (CMD_VARARG (str))
2113 varflag = 1;
2114
2115 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
2116 argv[argc++] = vector_slot (vline, i);
2117 }
2118 else
2119 argv[argc++] = vector_slot (vline, i);
2120 }
2121
2122 if (argc >= CMD_ARGC_MAX)
2123 return CMD_ERR_EXEED_ARGC_MAX;
2124 }
2125
2126 /* For vtysh execution. */
2127 if (cmd)
2128 *cmd = matched_element;
2129
2130 if (matched_element->daemon)
2131 return CMD_SUCCESS_DAEMON;
2132
2133 /* Now execute matched command */
2134 return (*matched_element->func) (matched_element, vty, argc, argv);
2135}
2136
2137/* Configration make from file. */
2138int
2139config_from_file (struct vty *vty, FILE *fp)
2140{
2141 int ret;
2142 vector vline;
2143
2144 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2145 {
2146 vline = cmd_make_strvec (vty->buf);
2147
2148 /* In case of comment line */
2149 if (vline == NULL)
2150 continue;
2151 /* Execute configuration command : this is strict match */
2152 ret = cmd_execute_command_strict (vline, vty, NULL);
2153
2154 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002155 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2156 && vty->node != CONFIG_NODE)
paul9ab68122003-01-18 01:16:20 +00002157 {
paulb92938a2002-12-13 21:20:42 +00002158 vty->node = node_parent(vty->node);
paul9ab68122003-01-18 01:16:20 +00002159 ret = cmd_execute_command_strict (vline, vty, NULL);
2160 }
2161
paul718e3742002-12-13 20:15:29 +00002162 cmd_free_strvec (vline);
2163
2164 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
2165 return ret;
2166 }
2167 return CMD_SUCCESS;
2168}
2169
2170/* Configration from terminal */
2171DEFUN (config_terminal,
2172 config_terminal_cmd,
2173 "configure terminal",
2174 "Configuration from vty interface\n"
2175 "Configuration terminal\n")
2176{
2177 if (vty_config_lock (vty))
2178 vty->node = CONFIG_NODE;
2179 else
2180 {
2181 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2182 return CMD_WARNING;
2183 }
2184 return CMD_SUCCESS;
2185}
2186
2187/* Enable command */
2188DEFUN (enable,
2189 config_enable_cmd,
2190 "enable",
2191 "Turn on privileged mode command\n")
2192{
2193 /* If enable password is NULL, change to ENABLE_NODE */
2194 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2195 vty->type == VTY_SHELL_SERV)
2196 vty->node = ENABLE_NODE;
2197 else
2198 vty->node = AUTH_ENABLE_NODE;
2199
2200 return CMD_SUCCESS;
2201}
2202
2203/* Disable command */
2204DEFUN (disable,
2205 config_disable_cmd,
2206 "disable",
2207 "Turn off privileged mode command\n")
2208{
2209 if (vty->node == ENABLE_NODE)
2210 vty->node = VIEW_NODE;
2211 return CMD_SUCCESS;
2212}
2213
2214/* Down vty node level. */
2215DEFUN (config_exit,
2216 config_exit_cmd,
2217 "exit",
2218 "Exit current mode and down to previous mode\n")
2219{
2220 switch (vty->node)
2221 {
2222 case VIEW_NODE:
2223 case ENABLE_NODE:
2224 if (vty_shell (vty))
2225 exit (0);
2226 else
2227 vty->status = VTY_CLOSE;
2228 break;
2229 case CONFIG_NODE:
2230 vty->node = ENABLE_NODE;
2231 vty_config_unlock (vty);
2232 break;
2233 case INTERFACE_NODE:
2234 case ZEBRA_NODE:
2235 case BGP_NODE:
2236 case RIP_NODE:
2237 case RIPNG_NODE:
2238 case OSPF_NODE:
2239 case OSPF6_NODE:
2240 case KEYCHAIN_NODE:
2241 case MASC_NODE:
2242 case RMAP_NODE:
2243 case VTY_NODE:
2244 vty->node = CONFIG_NODE;
2245 break;
2246 case BGP_VPNV4_NODE:
2247 case BGP_IPV4_NODE:
2248 case BGP_IPV4M_NODE:
2249 case BGP_IPV6_NODE:
2250 vty->node = BGP_NODE;
2251 break;
2252 case KEYCHAIN_KEY_NODE:
2253 vty->node = KEYCHAIN_NODE;
2254 break;
2255 default:
2256 break;
2257 }
2258 return CMD_SUCCESS;
2259}
2260
2261/* quit is alias of exit. */
2262ALIAS (config_exit,
2263 config_quit_cmd,
2264 "quit",
2265 "Exit current mode and down to previous mode\n")
2266
2267/* End of configuration. */
2268DEFUN (config_end,
2269 config_end_cmd,
2270 "end",
2271 "End current mode and change to enable mode.")
2272{
2273 switch (vty->node)
2274 {
2275 case VIEW_NODE:
2276 case ENABLE_NODE:
2277 /* Nothing to do. */
2278 break;
2279 case CONFIG_NODE:
2280 case INTERFACE_NODE:
2281 case ZEBRA_NODE:
2282 case RIP_NODE:
2283 case RIPNG_NODE:
2284 case BGP_NODE:
2285 case BGP_VPNV4_NODE:
2286 case BGP_IPV4_NODE:
2287 case BGP_IPV4M_NODE:
2288 case BGP_IPV6_NODE:
2289 case RMAP_NODE:
2290 case OSPF_NODE:
2291 case OSPF6_NODE:
2292 case KEYCHAIN_NODE:
2293 case KEYCHAIN_KEY_NODE:
2294 case MASC_NODE:
2295 case VTY_NODE:
2296 vty_config_unlock (vty);
2297 vty->node = ENABLE_NODE;
2298 break;
2299 default:
2300 break;
2301 }
2302 return CMD_SUCCESS;
2303}
2304
2305/* Show version. */
2306DEFUN (show_version,
2307 show_version_cmd,
2308 "show version",
2309 SHOW_STR
2310 "Displays zebra version\n")
2311{
2312 vty_out (vty, "Zebra %s (%s).%s", ZEBRA_VERSION,
2313 host_name,
2314 VTY_NEWLINE);
2315 vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
2316
2317 return CMD_SUCCESS;
2318}
2319
2320/* Help display function for all node. */
2321DEFUN (config_help,
2322 config_help_cmd,
2323 "help",
2324 "Description of the interactive help system\n")
2325{
2326 vty_out (vty,
2327 "Zebra VTY provides advanced help feature. When you need help,%s\
2328anytime at the command line please press '?'.%s\
2329%s\
2330If nothing matches, the help list will be empty and you must backup%s\
2331 until entering a '?' shows the available options.%s\
2332Two styles of help are provided:%s\
23331. Full help is available when you are ready to enter a%s\
2334command argument (e.g. 'show ?') and describes each possible%s\
2335argument.%s\
23362. Partial help is provided when an abbreviated argument is entered%s\
2337 and you want to know what arguments match the input%s\
2338 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2339 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2340 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2341 return CMD_SUCCESS;
2342}
2343
2344/* Help display function for all node. */
2345DEFUN (config_list,
2346 config_list_cmd,
2347 "list",
2348 "Print command list\n")
2349{
2350 int i;
2351 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2352 struct cmd_element *cmd;
2353
2354 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2355 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2356 vty_out (vty, " %s%s", cmd->string,
2357 VTY_NEWLINE);
2358 return CMD_SUCCESS;
2359}
2360
2361/* Write current configuration into file. */
2362DEFUN (config_write_file,
2363 config_write_file_cmd,
2364 "write file",
2365 "Write running configuration to memory, network, or terminal\n"
2366 "Write to configuration file\n")
2367{
2368 int i;
2369 int fd;
2370 struct cmd_node *node;
2371 char *config_file;
2372 char *config_file_tmp = NULL;
2373 char *config_file_sav = NULL;
2374 struct vty *file_vty;
2375
2376 /* Check and see if we are operating under vtysh configuration */
2377 if (host.config == NULL)
2378 {
2379 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2380 VTY_NEWLINE);
2381 return CMD_WARNING;
2382 }
2383
2384 /* Get filename. */
2385 config_file = host.config;
2386
2387 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2388 strcpy (config_file_sav, config_file);
2389 strcat (config_file_sav, CONF_BACKUP_EXT);
2390
2391
2392 config_file_tmp = malloc (strlen (config_file) + 8);
2393 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2394
2395 /* Open file to configuration write. */
2396 fd = mkstemp (config_file_tmp);
2397 if (fd < 0)
2398 {
2399 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2400 VTY_NEWLINE);
2401 free (config_file_tmp);
2402 free (config_file_sav);
2403 return CMD_WARNING;
2404 }
2405
2406 /* Make vty for configuration file. */
2407 file_vty = vty_new ();
2408 file_vty->fd = fd;
2409 file_vty->type = VTY_FILE;
2410
2411 /* Config file header print. */
2412 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2413 vty_time_print (file_vty, 1);
2414 vty_out (file_vty, "!\n");
2415
2416 for (i = 0; i < vector_max (cmdvec); i++)
2417 if ((node = vector_slot (cmdvec, i)) && node->func)
2418 {
2419 if ((*node->func) (file_vty))
2420 vty_out (file_vty, "!\n");
2421 }
2422 vty_close (file_vty);
2423
2424 if (unlink (config_file_sav) != 0)
2425 if (errno != ENOENT)
2426 {
2427 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2428 VTY_NEWLINE);
2429 free (config_file_sav);
2430 free (config_file_tmp);
2431 unlink (config_file_tmp);
2432 return CMD_WARNING;
2433 }
2434 if (link (config_file, config_file_sav) != 0)
2435 {
2436 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2437 VTY_NEWLINE);
2438 free (config_file_sav);
2439 free (config_file_tmp);
2440 unlink (config_file_tmp);
2441 return CMD_WARNING;
2442 }
2443 sync ();
2444 if (unlink (config_file) != 0)
2445 {
2446 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2447 VTY_NEWLINE);
2448 free (config_file_sav);
2449 free (config_file_tmp);
2450 unlink (config_file_tmp);
2451 return CMD_WARNING;
2452 }
2453 if (link (config_file_tmp, config_file) != 0)
2454 {
2455 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2456 VTY_NEWLINE);
2457 free (config_file_sav);
2458 free (config_file_tmp);
2459 unlink (config_file_tmp);
2460 return CMD_WARNING;
2461 }
2462 unlink (config_file_tmp);
2463 sync ();
2464
2465 free (config_file_sav);
2466 free (config_file_tmp);
2467 vty_out (vty, "Configuration saved to %s%s", config_file,
2468 VTY_NEWLINE);
2469 return CMD_SUCCESS;
2470}
2471
2472ALIAS (config_write_file,
2473 config_write_cmd,
2474 "write",
2475 "Write running configuration to memory, network, or terminal\n")
2476
2477ALIAS (config_write_file,
2478 config_write_memory_cmd,
2479 "write memory",
2480 "Write running configuration to memory, network, or terminal\n"
2481 "Write configuration to the file (same as write file)\n")
2482
2483ALIAS (config_write_file,
2484 copy_runningconfig_startupconfig_cmd,
2485 "copy running-config startup-config",
2486 "Copy configuration\n"
2487 "Copy running config to... \n"
2488 "Copy running config to startup config (same as write file)\n")
2489
2490/* Write current configuration into the terminal. */
2491DEFUN (config_write_terminal,
2492 config_write_terminal_cmd,
2493 "write terminal",
2494 "Write running configuration to memory, network, or terminal\n"
2495 "Write to terminal\n")
2496{
2497 int i;
2498 struct cmd_node *node;
2499
2500 if (vty->type == VTY_SHELL_SERV)
2501 {
2502 for (i = 0; i < vector_max (cmdvec); i++)
2503 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2504 {
2505 if ((*node->func) (vty))
2506 vty_out (vty, "!%s", VTY_NEWLINE);
2507 }
2508 }
2509 else
2510 {
2511 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2512 VTY_NEWLINE);
2513 vty_out (vty, "!%s", VTY_NEWLINE);
2514
2515 for (i = 0; i < vector_max (cmdvec); i++)
2516 if ((node = vector_slot (cmdvec, i)) && node->func)
2517 {
2518 if ((*node->func) (vty))
2519 vty_out (vty, "!%s", VTY_NEWLINE);
2520 }
2521 vty_out (vty, "end%s",VTY_NEWLINE);
2522 }
2523 return CMD_SUCCESS;
2524}
2525
2526/* Write current configuration into the terminal. */
2527ALIAS (config_write_terminal,
2528 show_running_config_cmd,
2529 "show running-config",
2530 SHOW_STR
2531 "running configuration\n")
2532
2533/* Write startup configuration into the terminal. */
2534DEFUN (show_startup_config,
2535 show_startup_config_cmd,
2536 "show startup-config",
2537 SHOW_STR
2538 "Contentes of startup configuration\n")
2539{
2540 char buf[BUFSIZ];
2541 FILE *confp;
2542
2543 confp = fopen (host.config, "r");
2544 if (confp == NULL)
2545 {
2546 vty_out (vty, "Can't open configuration file [%s]%s",
2547 host.config, VTY_NEWLINE);
2548 return CMD_WARNING;
2549 }
2550
2551 while (fgets (buf, BUFSIZ, confp))
2552 {
2553 char *cp = buf;
2554
2555 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2556 cp++;
2557 *cp = '\0';
2558
2559 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2560 }
2561
2562 fclose (confp);
2563
2564 return CMD_SUCCESS;
2565}
2566
2567/* Hostname configuration */
2568DEFUN (config_hostname,
2569 hostname_cmd,
2570 "hostname WORD",
2571 "Set system's network name\n"
2572 "This system's network name\n")
2573{
2574 if (!isalpha((int) *argv[0]))
2575 {
2576 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2577 return CMD_WARNING;
2578 }
2579
2580 if (host.name)
2581 XFREE (0, host.name);
2582
2583 host.name = strdup (argv[0]);
2584 return CMD_SUCCESS;
2585}
2586
2587DEFUN (config_no_hostname,
2588 no_hostname_cmd,
2589 "no hostname [HOSTNAME]",
2590 NO_STR
2591 "Reset system's network name\n"
2592 "Host name of this router\n")
2593{
2594 if (host.name)
2595 XFREE (0, host.name);
2596 host.name = NULL;
2597 return CMD_SUCCESS;
2598}
2599
2600/* VTY interface password set. */
2601DEFUN (config_password, password_cmd,
2602 "password (8|) WORD",
2603 "Assign the terminal connection password\n"
2604 "Specifies a HIDDEN password will follow\n"
2605 "dummy string \n"
2606 "The HIDDEN line password string\n")
2607{
2608 /* Argument check. */
2609 if (argc == 0)
2610 {
2611 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2612 return CMD_WARNING;
2613 }
2614
2615 if (argc == 2)
2616 {
2617 if (*argv[0] == '8')
2618 {
2619 if (host.password)
2620 XFREE (0, host.password);
2621 host.password = NULL;
2622 if (host.password_encrypt)
2623 XFREE (0, host.password_encrypt);
2624 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2625 return CMD_SUCCESS;
2626 }
2627 else
2628 {
2629 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2630 return CMD_WARNING;
2631 }
2632 }
2633
2634 if (!isalnum ((int) *argv[0]))
2635 {
2636 vty_out (vty,
2637 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2638 return CMD_WARNING;
2639 }
2640
2641 if (host.password)
2642 XFREE (0, host.password);
2643 host.password = NULL;
2644
2645 if (host.encrypt)
2646 {
2647 if (host.password_encrypt)
2648 XFREE (0, host.password_encrypt);
2649 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2650 }
2651 else
2652 host.password = XSTRDUP (0, argv[0]);
2653
2654 return CMD_SUCCESS;
2655}
2656
2657ALIAS (config_password, password_text_cmd,
2658 "password LINE",
2659 "Assign the terminal connection password\n"
2660 "The UNENCRYPTED (cleartext) line password\n")
2661
2662/* VTY enable password set. */
2663DEFUN (config_enable_password, enable_password_cmd,
2664 "enable password (8|) WORD",
2665 "Modify enable password parameters\n"
2666 "Assign the privileged level password\n"
2667 "Specifies a HIDDEN password will follow\n"
2668 "dummy string \n"
2669 "The HIDDEN 'enable' password string\n")
2670{
2671 /* Argument check. */
2672 if (argc == 0)
2673 {
2674 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2675 return CMD_WARNING;
2676 }
2677
2678 /* Crypt type is specified. */
2679 if (argc == 2)
2680 {
2681 if (*argv[0] == '8')
2682 {
2683 if (host.enable)
2684 XFREE (0, host.enable);
2685 host.enable = NULL;
2686
2687 if (host.enable_encrypt)
2688 XFREE (0, host.enable_encrypt);
2689 host.enable_encrypt = XSTRDUP (0, argv[1]);
2690
2691 return CMD_SUCCESS;
2692 }
2693 else
2694 {
2695 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2696 return CMD_WARNING;
2697 }
2698 }
2699
2700 if (!isalnum ((int) *argv[0]))
2701 {
2702 vty_out (vty,
2703 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2704 return CMD_WARNING;
2705 }
2706
2707 if (host.enable)
2708 XFREE (0, host.enable);
2709 host.enable = NULL;
2710
2711 /* Plain password input. */
2712 if (host.encrypt)
2713 {
2714 if (host.enable_encrypt)
2715 XFREE (0, host.enable_encrypt);
2716 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2717 }
2718 else
2719 host.enable = XSTRDUP (0, argv[0]);
2720
2721 return CMD_SUCCESS;
2722}
2723
2724ALIAS (config_enable_password,
2725 enable_password_text_cmd,
2726 "enable password LINE",
2727 "Modify enable password parameters\n"
2728 "Assign the privileged level password\n"
2729 "The UNENCRYPTED (cleartext) 'enable' password\n")
2730
2731/* VTY enable password delete. */
2732DEFUN (no_config_enable_password, no_enable_password_cmd,
2733 "no enable password",
2734 NO_STR
2735 "Modify enable password parameters\n"
2736 "Assign the privileged level password\n")
2737{
2738 if (host.enable)
2739 XFREE (0, host.enable);
2740 host.enable = NULL;
2741
2742 if (host.enable_encrypt)
2743 XFREE (0, host.enable_encrypt);
2744 host.enable_encrypt = NULL;
2745
2746 return CMD_SUCCESS;
2747}
2748
2749DEFUN (service_password_encrypt,
2750 service_password_encrypt_cmd,
2751 "service password-encryption",
2752 "Set up miscellaneous service\n"
2753 "Enable encrypted passwords\n")
2754{
2755 if (host.encrypt)
2756 return CMD_SUCCESS;
2757
2758 host.encrypt = 1;
2759
2760 if (host.password)
2761 {
2762 if (host.password_encrypt)
2763 XFREE (0, host.password_encrypt);
2764 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2765 }
2766 if (host.enable)
2767 {
2768 if (host.enable_encrypt)
2769 XFREE (0, host.enable_encrypt);
2770 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2771 }
2772
2773 return CMD_SUCCESS;
2774}
2775
2776DEFUN (no_service_password_encrypt,
2777 no_service_password_encrypt_cmd,
2778 "no service password-encryption",
2779 NO_STR
2780 "Set up miscellaneous service\n"
2781 "Enable encrypted passwords\n")
2782{
2783 if (! host.encrypt)
2784 return CMD_SUCCESS;
2785
2786 host.encrypt = 0;
2787
2788 if (host.password_encrypt)
2789 XFREE (0, host.password_encrypt);
2790 host.password_encrypt = NULL;
2791
2792 if (host.enable_encrypt)
2793 XFREE (0, host.enable_encrypt);
2794 host.enable_encrypt = NULL;
2795
2796 return CMD_SUCCESS;
2797}
2798
2799DEFUN (config_terminal_length, config_terminal_length_cmd,
2800 "terminal length <0-512>",
2801 "Set terminal line parameters\n"
2802 "Set number of lines on a screen\n"
2803 "Number of lines on screen (0 for no pausing)\n")
2804{
2805 int lines;
2806 char *endptr = NULL;
2807
2808 lines = strtol (argv[0], &endptr, 10);
2809 if (lines < 0 || lines > 512 || *endptr != '\0')
2810 {
2811 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2812 return CMD_WARNING;
2813 }
2814 vty->lines = lines;
2815
2816 return CMD_SUCCESS;
2817}
2818
2819DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2820 "terminal no length",
2821 "Set terminal line parameters\n"
2822 NO_STR
2823 "Set number of lines on a screen\n")
2824{
2825 vty->lines = -1;
2826 return CMD_SUCCESS;
2827}
2828
2829DEFUN (service_terminal_length, service_terminal_length_cmd,
2830 "service terminal-length <0-512>",
2831 "Set up miscellaneous service\n"
2832 "System wide terminal length configuration\n"
2833 "Number of lines of VTY (0 means no line control)\n")
2834{
2835 int lines;
2836 char *endptr = NULL;
2837
2838 lines = strtol (argv[0], &endptr, 10);
2839 if (lines < 0 || lines > 512 || *endptr != '\0')
2840 {
2841 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2842 return CMD_WARNING;
2843 }
2844 host.lines = lines;
2845
2846 return CMD_SUCCESS;
2847}
2848
2849DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2850 "no service terminal-length [<0-512>]",
2851 NO_STR
2852 "Set up miscellaneous service\n"
2853 "System wide terminal length configuration\n"
2854 "Number of lines of VTY (0 means no line control)\n")
2855{
2856 host.lines = -1;
2857 return CMD_SUCCESS;
2858}
2859
2860DEFUN (config_log_stdout,
2861 config_log_stdout_cmd,
2862 "log stdout",
2863 "Logging control\n"
2864 "Logging goes to stdout\n")
2865{
2866 zlog_set_flag (NULL, ZLOG_STDOUT);
2867 host.log_stdout = 1;
2868 return CMD_SUCCESS;
2869}
2870
2871DEFUN (no_config_log_stdout,
2872 no_config_log_stdout_cmd,
2873 "no log stdout",
2874 NO_STR
2875 "Logging control\n"
2876 "Cancel logging to stdout\n")
2877{
2878 zlog_reset_flag (NULL, ZLOG_STDOUT);
2879 host.log_stdout = 0;
2880 return CMD_SUCCESS;
2881}
2882
2883DEFUN (config_log_file,
2884 config_log_file_cmd,
2885 "log file FILENAME",
2886 "Logging control\n"
2887 "Logging to file\n"
2888 "Logging filename\n")
2889{
2890 int ret;
2891 char *cwd;
2892 char *fullpath;
2893
2894 /* Path detection. */
2895 if (! IS_DIRECTORY_SEP (*argv[0]))
2896 {
2897 cwd = getcwd (NULL, MAXPATHLEN);
2898 fullpath = XMALLOC (MTYPE_TMP,
2899 strlen (cwd) + strlen (argv[0]) + 2);
2900 sprintf (fullpath, "%s/%s", cwd, argv[0]);
2901 }
2902 else
2903 fullpath = argv[0];
2904
2905 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
2906
2907 if (!ret)
2908 {
2909 vty_out (vty, "can't open logfile %s\n", argv[0]);
2910 return CMD_WARNING;
2911 }
2912
2913 if (host.logfile)
2914 XFREE (MTYPE_TMP, host.logfile);
2915
2916 host.logfile = strdup (argv[0]);
2917
2918 return CMD_SUCCESS;
2919}
2920
2921DEFUN (no_config_log_file,
2922 no_config_log_file_cmd,
2923 "no log file [FILENAME]",
2924 NO_STR
2925 "Logging control\n"
2926 "Cancel logging to file\n"
2927 "Logging file name\n")
2928{
2929 zlog_reset_file (NULL);
2930
2931 if (host.logfile)
2932 XFREE (MTYPE_TMP, host.logfile);
2933
2934 host.logfile = NULL;
2935
2936 return CMD_SUCCESS;
2937}
2938
2939DEFUN (config_log_syslog,
2940 config_log_syslog_cmd,
2941 "log syslog",
2942 "Logging control\n"
2943 "Logging goes to syslog\n")
2944{
2945 zlog_set_flag (NULL, ZLOG_SYSLOG);
2946 host.log_syslog = 1;
2947 return CMD_SUCCESS;
2948}
2949
2950DEFUN (no_config_log_syslog,
2951 no_config_log_syslog_cmd,
2952 "no log syslog",
2953 NO_STR
2954 "Logging control\n"
2955 "Cancel logging to syslog\n")
2956{
2957 zlog_reset_flag (NULL, ZLOG_SYSLOG);
2958 host.log_syslog = 0;
2959 return CMD_SUCCESS;
2960}
2961
2962DEFUN (config_log_trap,
2963 config_log_trap_cmd,
2964 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
2965 "Logging control\n"
2966 "Limit logging to specifed level\n")
2967{
2968 int new_level ;
2969
2970 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
2971 {
2972 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
2973 /* found new logging level */
2974 {
2975 zlog_default->maskpri = new_level;
2976 return CMD_SUCCESS;
2977 }
2978 }
2979 return CMD_ERR_NO_MATCH;
2980}
2981
2982DEFUN (no_config_log_trap,
2983 no_config_log_trap_cmd,
2984 "no log trap",
2985 NO_STR
2986 "Logging control\n"
2987 "Permit all logging information\n")
2988{
2989 zlog_default->maskpri = LOG_DEBUG;
2990 return CMD_SUCCESS;
2991}
2992
2993DEFUN (config_log_record_priority,
2994 config_log_record_priority_cmd,
2995 "log record-priority",
2996 "Logging control\n"
2997 "Log the priority of the message within the message\n")
2998{
2999 zlog_default->record_priority = 1 ;
3000 return CMD_SUCCESS;
3001}
3002
3003DEFUN (no_config_log_record_priority,
3004 no_config_log_record_priority_cmd,
3005 "no log record-priority",
3006 NO_STR
3007 "Logging control\n"
3008 "Do not log the priority of the message within the message\n")
3009{
3010 zlog_default->record_priority = 0 ;
3011 return CMD_SUCCESS;
3012}
3013
3014
3015DEFUN (banner_motd_default,
3016 banner_motd_default_cmd,
3017 "banner motd default",
3018 "Set banner string\n"
3019 "Strings for motd\n"
3020 "Default string\n")
3021{
3022 host.motd = default_motd;
3023 return CMD_SUCCESS;
3024}
3025
3026DEFUN (no_banner_motd,
3027 no_banner_motd_cmd,
3028 "no banner motd",
3029 NO_STR
3030 "Set banner string\n"
3031 "Strings for motd\n")
3032{
3033 host.motd = NULL;
3034 return CMD_SUCCESS;
3035}
3036
3037/* Set config filename. Called from vty.c */
3038void
3039host_config_set (char *filename)
3040{
3041 host.config = strdup (filename);
3042}
3043
3044void
3045install_default (enum node_type node)
3046{
3047 install_element (node, &config_exit_cmd);
3048 install_element (node, &config_quit_cmd);
3049 install_element (node, &config_end_cmd);
3050 install_element (node, &config_help_cmd);
3051 install_element (node, &config_list_cmd);
3052
3053 install_element (node, &config_write_terminal_cmd);
3054 install_element (node, &config_write_file_cmd);
3055 install_element (node, &config_write_memory_cmd);
3056 install_element (node, &config_write_cmd);
3057 install_element (node, &show_running_config_cmd);
3058}
3059
3060/* Initialize command interface. Install basic nodes and commands. */
3061void
3062cmd_init (int terminal)
3063{
3064 /* Allocate initial top vector of commands. */
3065 cmdvec = vector_init (VECTOR_MIN_SIZE);
3066
3067 /* Default host value settings. */
3068 host.name = NULL;
3069 host.password = NULL;
3070 host.enable = NULL;
3071 host.logfile = NULL;
3072 host.config = NULL;
3073 host.lines = -1;
3074 host.motd = default_motd;
3075
3076 /* Install top nodes. */
3077 install_node (&view_node, NULL);
3078 install_node (&enable_node, NULL);
3079 install_node (&auth_node, NULL);
3080 install_node (&auth_enable_node, NULL);
3081 install_node (&config_node, config_write_host);
3082
3083 /* Each node's basic commands. */
3084 install_element (VIEW_NODE, &show_version_cmd);
3085 if (terminal)
3086 {
3087 install_element (VIEW_NODE, &config_list_cmd);
3088 install_element (VIEW_NODE, &config_exit_cmd);
3089 install_element (VIEW_NODE, &config_quit_cmd);
3090 install_element (VIEW_NODE, &config_help_cmd);
3091 install_element (VIEW_NODE, &config_enable_cmd);
3092 install_element (VIEW_NODE, &config_terminal_length_cmd);
3093 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3094 }
3095
3096 if (terminal)
3097 {
3098 install_default (ENABLE_NODE);
3099 install_element (ENABLE_NODE, &config_disable_cmd);
3100 install_element (ENABLE_NODE, &config_terminal_cmd);
3101 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3102 }
3103 install_element (ENABLE_NODE, &show_startup_config_cmd);
3104 install_element (ENABLE_NODE, &show_version_cmd);
3105 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3106 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3107
3108 if (terminal)
3109 install_default (CONFIG_NODE);
3110 install_element (CONFIG_NODE, &hostname_cmd);
3111 install_element (CONFIG_NODE, &no_hostname_cmd);
3112 install_element (CONFIG_NODE, &password_cmd);
3113 install_element (CONFIG_NODE, &password_text_cmd);
3114 install_element (CONFIG_NODE, &enable_password_cmd);
3115 install_element (CONFIG_NODE, &enable_password_text_cmd);
3116 install_element (CONFIG_NODE, &no_enable_password_cmd);
3117 if (terminal)
3118 {
3119 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3120 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3121 install_element (CONFIG_NODE, &config_log_file_cmd);
3122 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3123 install_element (CONFIG_NODE, &config_log_syslog_cmd);
3124 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
3125 install_element (CONFIG_NODE, &config_log_trap_cmd);
3126 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3127 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3128 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3129 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3130 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3131 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3132 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3133 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3134 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3135 }
3136
paul9ab68122003-01-18 01:16:20 +00003137 if (terminal)
3138 {
3139 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3140 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3141 }
paul718e3742002-12-13 20:15:29 +00003142 srand(time(NULL));
3143}