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