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