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