blob: e8c9203f4cccf19114e78451925ff213fbf8b874 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Command interpreter routine for virtual terminal [aka TeletYpe]
2 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation; either version 2, or (at your
9option) any later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include <zebra.h>
22
paulb21b19c2003-06-15 01:28:29 +000023
paul718e3742002-12-13 20:15:29 +000024#include "memory.h"
25#include "log.h"
26#include "version.h"
paul9ab68122003-01-18 01:16:20 +000027#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000028#include "vector.h"
29#include "vty.h"
30#include "command.h"
paul718e3742002-12-13 20:15:29 +000031
32/* Command vector which includes some level of command lists. Normally
33 each daemon maintains each own cmdvec. */
34vector cmdvec;
35
36/* Host information structure. */
37struct host host;
38
39/* Default motd string. */
40char *default_motd =
41"\r\n\
paul42053f42003-08-13 02:54:44 +000042Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
paul718e3742002-12-13 20:15:29 +000043Copyright 1996-2002 Kunihiro Ishiguro.\r\n\
44\r\n";
45
46/* Standard command node structures. */
47struct cmd_node auth_node =
48{
49 AUTH_NODE,
50 "Password: ",
51};
52
53struct cmd_node view_node =
54{
55 VIEW_NODE,
56 "%s> ",
57};
58
59struct cmd_node auth_enable_node =
60{
61 AUTH_ENABLE_NODE,
62 "Password: ",
63};
64
65struct cmd_node enable_node =
66{
67 ENABLE_NODE,
68 "%s# ",
69};
70
71struct cmd_node config_node =
72{
73 CONFIG_NODE,
74 "%s(config)# ",
75 1
76};
77
78/* Utility function to concatenate argv argument into a single string
79 with inserting ' ' character between each argument. */
80char *
81argv_concat (char **argv, int argc, int shift)
82{
83 int i;
84 int len;
85 int index;
86 char *str;
87
88 str = NULL;
89 index = 0;
90
91 for (i = shift; i < argc; i++)
92 {
93 len = strlen (argv[i]);
94
95 if (i == shift)
96 {
97 str = XSTRDUP (MTYPE_TMP, argv[i]);
98 index = len;
99 }
100 else
101 {
102 str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
103 str[index++] = ' ';
104 memcpy (str + index, argv[i], len);
105 index += len;
106 str[index] = '\0';
107 }
108 }
109 return str;
110}
111
112/* Install top node of command vector. */
113void
114install_node (struct cmd_node *node,
115 int (*func) (struct vty *))
116{
117 vector_set_index (cmdvec, node->node, node);
118 node->func = func;
119 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
120}
121
122/* Compare two command's string. Used in sort_node (). */
123int
124cmp_node (const void *p, const void *q)
125{
126 struct cmd_element *a = *(struct cmd_element **)p;
127 struct cmd_element *b = *(struct cmd_element **)q;
128
129 return strcmp (a->string, b->string);
130}
131
132int
133cmp_desc (const void *p, const void *q)
134{
135 struct desc *a = *(struct desc **)p;
136 struct desc *b = *(struct desc **)q;
137
138 return strcmp (a->cmd, b->cmd);
139}
140
141/* Sort each node's command element according to command string. */
142void
143sort_node ()
144{
145 int i, j;
146 struct cmd_node *cnode;
147 vector descvec;
148 struct cmd_element *cmd_element;
149
150 for (i = 0; i < vector_max (cmdvec); i++)
151 if ((cnode = vector_slot (cmdvec, i)) != NULL)
152 {
153 vector cmd_vector = cnode->cmd_vector;
154 qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
155
156 for (j = 0; j < vector_max (cmd_vector); j++)
157 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
158 {
159 descvec = vector_slot (cmd_element->strvec,
160 vector_max (cmd_element->strvec) - 1);
161 qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
162 }
163 }
164}
165
166/* Breaking up string into each command piece. I assume given
167 character is separated by a space character. Return value is a
168 vector which includes char ** data element. */
169vector
170cmd_make_strvec (char *string)
171{
172 char *cp, *start, *token;
173 int strlen;
174 vector strvec;
175
176 if (string == NULL)
177 return NULL;
178
179 cp = string;
180
181 /* Skip white spaces. */
182 while (isspace ((int) *cp) && *cp != '\0')
183 cp++;
184
185 /* Return if there is only white spaces */
186 if (*cp == '\0')
187 return NULL;
188
189 if (*cp == '!' || *cp == '#')
190 return NULL;
191
192 /* Prepare return vector. */
193 strvec = vector_init (VECTOR_MIN_SIZE);
194
195 /* Copy each command piece and set into vector. */
196 while (1)
197 {
198 start = cp;
199 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
200 *cp != '\0')
201 cp++;
202 strlen = cp - start;
203 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
204 memcpy (token, start, strlen);
205 *(token + strlen) = '\0';
206 vector_set (strvec, token);
207
208 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
209 *cp != '\0')
210 cp++;
211
212 if (*cp == '\0')
213 return strvec;
214 }
215}
216
217/* Free allocated string vector. */
218void
219cmd_free_strvec (vector v)
220{
221 int i;
222 char *cp;
223
224 if (!v)
225 return;
226
227 for (i = 0; i < vector_max (v); i++)
228 if ((cp = vector_slot (v, i)) != NULL)
229 XFREE (MTYPE_STRVEC, cp);
230
231 vector_free (v);
232}
233
234/* Fetch next description. Used in cmd_make_descvec(). */
235char *
236cmd_desc_str (char **string)
237{
238 char *cp, *start, *token;
239 int strlen;
240
241 cp = *string;
242
243 if (cp == NULL)
244 return NULL;
245
246 /* Skip white spaces. */
247 while (isspace ((int) *cp) && *cp != '\0')
248 cp++;
249
250 /* Return if there is only white spaces */
251 if (*cp == '\0')
252 return NULL;
253
254 start = cp;
255
256 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
257 cp++;
258
259 strlen = cp - start;
260 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
261 memcpy (token, start, strlen);
262 *(token + strlen) = '\0';
263
264 *string = cp;
265
266 return token;
267}
268
269/* New string vector. */
270vector
271cmd_make_descvec (char *string, char *descstr)
272{
273 int multiple = 0;
274 char *sp;
275 char *token;
276 int len;
277 char *cp;
278 char *dp;
279 vector allvec;
280 vector strvec = NULL;
281 struct desc *desc;
282
283 cp = string;
284 dp = descstr;
285
286 if (cp == NULL)
287 return NULL;
288
289 allvec = vector_init (VECTOR_MIN_SIZE);
290
291 while (1)
292 {
293 while (isspace ((int) *cp) && *cp != '\0')
294 cp++;
295
296 if (*cp == '(')
297 {
298 multiple = 1;
299 cp++;
300 }
301 if (*cp == ')')
302 {
303 multiple = 0;
304 cp++;
305 }
306 if (*cp == '|')
307 {
308 if (! multiple)
309 {
310 fprintf (stderr, "Command parse error!: %s\n", string);
311 exit (1);
312 }
313 cp++;
314 }
315
316 while (isspace ((int) *cp) && *cp != '\0')
317 cp++;
318
319 if (*cp == '(')
320 {
321 multiple = 1;
322 cp++;
323 }
324
325 if (*cp == '\0')
326 return allvec;
327
328 sp = cp;
329
330 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
331 cp++;
332
333 len = cp - sp;
334
335 token = XMALLOC (MTYPE_STRVEC, len + 1);
336 memcpy (token, sp, len);
337 *(token + len) = '\0';
338
339 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
340 desc->cmd = token;
341 desc->str = cmd_desc_str (&dp);
342
343 if (multiple)
344 {
345 if (multiple == 1)
346 {
347 strvec = vector_init (VECTOR_MIN_SIZE);
348 vector_set (allvec, strvec);
349 }
350 multiple++;
351 }
352 else
353 {
354 strvec = vector_init (VECTOR_MIN_SIZE);
355 vector_set (allvec, strvec);
356 }
357 vector_set (strvec, desc);
358 }
359}
360
361/* Count mandantory string vector size. This is to determine inputed
362 command has enough command length. */
363int
364cmd_cmdsize (vector strvec)
365{
366 int i;
367 char *str;
368 int size = 0;
369 vector descvec;
370
371 for (i = 0; i < vector_max (strvec); i++)
372 {
373 descvec = vector_slot (strvec, i);
374
375 if (vector_max (descvec) == 1)
376 {
377 struct desc *desc = vector_slot (descvec, 0);
378
379 str = desc->cmd;
380
381 if (str == NULL || CMD_OPTION (str))
382 return size;
383 else
384 size++;
385 }
386 else
387 size++;
388 }
389 return size;
390}
391
392/* Return prompt character of specified node. */
393char *
394cmd_prompt (enum node_type node)
395{
396 struct cmd_node *cnode;
397
398 cnode = vector_slot (cmdvec, node);
399 return cnode->prompt;
400}
401
402/* Install a command into a node. */
403void
404install_element (enum node_type ntype, struct cmd_element *cmd)
405{
406 struct cmd_node *cnode;
407
408 cnode = vector_slot (cmdvec, ntype);
409
410 if (cnode == NULL)
411 {
412 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
413 ntype);
414 exit (1);
415 }
416
417 vector_set (cnode->cmd_vector, cmd);
418
419 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
420 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
421}
422
423static unsigned char itoa64[] =
424"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
425
426void
427to64(char *s, long v, int n)
428{
429 while (--n >= 0)
430 {
431 *s++ = itoa64[v&0x3f];
432 v >>= 6;
433 }
434}
435
436char *zencrypt (char *passwd)
437{
438 char salt[6];
439 struct timeval tv;
440 char *crypt (const char *, const char *);
441
442 gettimeofday(&tv,0);
443
444 to64(&salt[0], random(), 3);
445 to64(&salt[3], tv.tv_usec, 3);
446 salt[5] = '\0';
447
448 return crypt (passwd, salt);
449}
450
paul12ab19f2003-07-26 06:14:55 +0000451char *
452syslog_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
paul718e3742002-12-13 20:15:29 +0000516/* This function write configuration of this host. */
517int
518config_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)
paul12ab19f2003-07-26 06:14:55 +0000545 {
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 }
paul718e3742002-12-13 20:15:29 +0000551 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. */
574vector
575cmd_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 */
582int
583cmd_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. */
627enum 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
641enum match_type
642cmd_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
698enum match_type
699cmd_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
paul22e0a9e2003-07-11 17:55:46 +0000787#ifdef HAVE_IPV6
788
paul718e3742002-12-13 20:15:29 +0000789enum match_type
790cmd_ipv6_match (char *str)
791{
792 int state = STATE_START;
793 int colons = 0, nums = 0, double_colon = 0;
794 char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000795 struct sockaddr_in6 sin6_dummy;
796 int ret;
paul718e3742002-12-13 20:15:29 +0000797
798 if (str == NULL)
799 return partly_match;
800
801 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
802 return no_match;
803
hasso726f9b22003-05-25 21:04:54 +0000804 /* 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
paul718e3742002-12-13 20:15:29 +0000813 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
895enum match_type
896cmd_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
paul22e0a9e2003-07-11 17:55:46 +00001026#endif /* HAVE_IPV6 */
1027
paul718e3742002-12-13 20:15:29 +00001028#define DECIMAL_STRLEN_MAX 10
1029
1030int
1031cmd_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. */
1076enum match_type
1077cmd_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 }
paul22e0a9e2003-07-11 17:55:46 +00001122#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001123 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 }
paul22e0a9e2003-07-11 17:55:46 +00001143#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001144 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. */
1191enum match_type
1192cmd_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 }
paul22e0a9e2003-07-11 17:55:46 +00001238#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001239 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 }
paul22e0a9e2003-07-11 17:55:46 +00001257#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001258 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 */
1299int
1300is_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;
paul22e0a9e2003-07-11 17:55:46 +00001352#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001353 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;
paul22e0a9e2003-07-11 17:55:46 +00001366#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001367 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 */
1396char *
1397cmd_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 */
1418char *
1419cmd_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
paul22e0a9e2003-07-11 17:55:46 +00001432#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001433 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 }
paul22e0a9e2003-07-11 17:55:46 +00001448#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001449
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. */
1482int
1483cmd_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. */
1497int
1498desc_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
paulb92938a2002-12-13 21:20:42 +00001510int
1511cmd_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
paul718e3742002-12-13 20:15:29 +00001522/* '?' describe command support. */
1523vector
paulb92938a2002-12-13 21:20:42 +00001524cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001525{
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 static struct desc desc_cr = { "<cr>", "" };
1533
1534 /* Set index. */
1535 index = vector_max (vline) - 1;
1536
1537 /* Make copy vector of current node's command vector. */
1538 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1539
1540 /* Prepare match vector */
1541 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1542
1543 /* Filter commands. */
1544 for (i = 0; i < index; i++)
1545 {
1546 enum match_type match;
1547 char *command;
1548 int ret;
1549
1550 command = vector_slot (vline, i);
1551
1552 match = cmd_filter_by_completion (command, cmd_vector, i);
1553
1554 if (match == vararg_match)
1555 {
1556 struct cmd_element *cmd_element;
1557 vector descvec;
1558 int j, k;
1559
1560 for (j = 0; j < vector_max (cmd_vector); j++)
1561 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1562 {
1563 descvec = vector_slot (cmd_element->strvec,
1564 vector_max (cmd_element->strvec) - 1);
1565 for (k = 0; k < vector_max (descvec); k++)
1566 {
1567 struct desc *desc = vector_slot (descvec, k);
1568 vector_set (matchvec, desc);
1569 }
1570 }
1571
1572 vector_set (matchvec, &desc_cr);
1573
1574 vector_free (cmd_vector);
1575
1576 return matchvec;
1577 }
1578
1579 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1580 {
1581 vector_free (cmd_vector);
1582 *status = CMD_ERR_AMBIGUOUS;
1583 return NULL;
1584 }
1585 else if (ret == 2)
1586 {
1587 vector_free (cmd_vector);
1588 *status = CMD_ERR_NO_MATCH;
1589 return NULL;
1590 }
1591 }
1592
1593 /* Prepare match vector */
1594 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1595
1596 /* Make description vector. */
1597 for (i = 0; i < vector_max (cmd_vector); i++)
1598 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1599 {
1600 char *string = NULL;
1601 vector strvec = cmd_element->strvec;
1602
1603 if (index > vector_max (strvec))
1604 vector_slot (cmd_vector, i) = NULL;
1605 else
1606 {
1607 /* Check is command is completed. */
1608 if (index == vector_max (strvec))
1609 {
1610 string = "<cr>";
1611 if (! desc_unique_string (matchvec, string))
1612 vector_set (matchvec, &desc_cr);
1613 }
1614 else
1615 {
1616 int j;
1617 vector descvec = vector_slot (strvec, index);
1618 struct desc *desc;
1619
1620 for (j = 0; j < vector_max (descvec); j++)
1621 {
1622 desc = vector_slot (descvec, j);
1623 string = cmd_entry_function_desc (vector_slot (vline, index), desc->cmd);
1624 if (string)
1625 {
1626 /* Uniqueness check */
1627 if (! desc_unique_string (matchvec, string))
1628 vector_set (matchvec, desc);
1629 }
1630 }
1631 }
1632 }
1633 }
1634 vector_free (cmd_vector);
1635
1636 if (vector_slot (matchvec, 0) == NULL)
1637 {
1638 vector_free (matchvec);
1639 *status= CMD_ERR_NO_MATCH;
1640 }
1641 else
1642 *status = CMD_SUCCESS;
1643
1644 return matchvec;
1645}
1646
paulb92938a2002-12-13 21:20:42 +00001647vector
1648cmd_describe_command (vector vline, struct vty *vty, int *status)
1649{
1650 vector ret;
1651
1652 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1653 {
1654 enum node_type onode;
1655 vector shifted_vline;
1656 int index;
1657
1658 onode = vty->node;
1659 vty->node = ENABLE_NODE;
1660 /* We can try it on enable node, cos' the vty is authenticated */
1661
1662 shifted_vline = vector_init (vector_count(vline));
1663 /* use memcpy? */
1664 for (index = 1; index < vector_max (vline); index++)
1665 {
1666 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1667 }
1668
1669 ret = cmd_describe_command_real (shifted_vline, vty, status);
1670
1671 vector_free(shifted_vline);
1672 vty->node = onode;
1673 return ret;
1674 }
1675
1676
1677 return cmd_describe_command_real (vline, vty, status);
1678}
1679
1680
paul718e3742002-12-13 20:15:29 +00001681/* Check LCD of matched command. */
1682int
1683cmd_lcd (char **matched)
1684{
1685 int i;
1686 int j;
1687 int lcd = -1;
1688 char *s1, *s2;
1689 char c1, c2;
1690
1691 if (matched[0] == NULL || matched[1] == NULL)
1692 return 0;
1693
1694 for (i = 1; matched[i] != NULL; i++)
1695 {
1696 s1 = matched[i - 1];
1697 s2 = matched[i];
1698
1699 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1700 if (c1 != c2)
1701 break;
1702
1703 if (lcd < 0)
1704 lcd = j;
1705 else
1706 {
1707 if (lcd > j)
1708 lcd = j;
1709 }
1710 }
1711 return lcd;
1712}
1713
1714/* Command line completion support. */
1715char **
paulb92938a2002-12-13 21:20:42 +00001716cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001717{
1718 int i;
1719 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1720#define INIT_MATCHVEC_SIZE 10
1721 vector matchvec;
1722 struct cmd_element *cmd_element;
1723 int index = vector_max (vline) - 1;
1724 char **match_str;
1725 struct desc *desc;
1726 vector descvec;
1727 char *command;
1728 int lcd;
1729
1730 /* First, filter by preceeding command string */
1731 for (i = 0; i < index; i++)
1732 {
1733 enum match_type match;
1734 int ret;
1735
1736 command = vector_slot (vline, i);
1737
1738 /* First try completion match, if there is exactly match return 1 */
1739 match = cmd_filter_by_completion (command, cmd_vector, i);
1740
1741 /* If there is exact match then filter ambiguous match else check
1742 ambiguousness. */
1743 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1744 {
1745 vector_free (cmd_vector);
1746 *status = CMD_ERR_AMBIGUOUS;
1747 return NULL;
1748 }
1749 /*
1750 else if (ret == 2)
1751 {
1752 vector_free (cmd_vector);
1753 *status = CMD_ERR_NO_MATCH;
1754 return NULL;
1755 }
1756 */
1757 }
1758
1759 /* Prepare match vector. */
1760 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1761
1762 /* Now we got into completion */
1763 for (i = 0; i < vector_max (cmd_vector); i++)
1764 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1765 {
1766 char *string;
1767 vector strvec = cmd_element->strvec;
1768
1769 /* Check field length */
1770 if (index >= vector_max (strvec))
1771 vector_slot (cmd_vector, i) = NULL;
1772 else
1773 {
1774 int j;
1775
1776 descvec = vector_slot (strvec, index);
1777 for (j = 0; j < vector_max (descvec); j++)
1778 {
1779 desc = vector_slot (descvec, j);
1780
1781 if ((string = cmd_entry_function (vector_slot (vline, index),
1782 desc->cmd)))
1783 if (cmd_unique_string (matchvec, string))
1784 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1785 }
1786 }
1787 }
1788
1789 /* We don't need cmd_vector any more. */
1790 vector_free (cmd_vector);
1791
1792 /* No matched command */
1793 if (vector_slot (matchvec, 0) == NULL)
1794 {
1795 vector_free (matchvec);
1796
1797 /* In case of 'command \t' pattern. Do you need '?' command at
1798 the end of the line. */
1799 if (vector_slot (vline, index) == '\0')
1800 *status = CMD_ERR_NOTHING_TODO;
1801 else
1802 *status = CMD_ERR_NO_MATCH;
1803 return NULL;
1804 }
1805
1806 /* Only one matched */
1807 if (vector_slot (matchvec, 1) == NULL)
1808 {
1809 match_str = (char **) matchvec->index;
1810 vector_only_wrapper_free (matchvec);
1811 *status = CMD_COMPLETE_FULL_MATCH;
1812 return match_str;
1813 }
1814 /* Make it sure last element is NULL. */
1815 vector_set (matchvec, NULL);
1816
1817 /* Check LCD of matched strings. */
1818 if (vector_slot (vline, index) != NULL)
1819 {
1820 lcd = cmd_lcd ((char **) matchvec->index);
1821
1822 if (lcd)
1823 {
1824 int len = strlen (vector_slot (vline, index));
1825
1826 if (len < lcd)
1827 {
1828 char *lcdstr;
1829
1830 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1831 memcpy (lcdstr, matchvec->index[0], lcd);
1832 lcdstr[lcd] = '\0';
1833
1834 /* match_str = (char **) &lcdstr; */
1835
1836 /* Free matchvec. */
1837 for (i = 0; i < vector_max (matchvec); i++)
1838 {
1839 if (vector_slot (matchvec, i))
1840 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1841 }
1842 vector_free (matchvec);
1843
1844 /* Make new matchvec. */
1845 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1846 vector_set (matchvec, lcdstr);
1847 match_str = (char **) matchvec->index;
1848 vector_only_wrapper_free (matchvec);
1849
1850 *status = CMD_COMPLETE_MATCH;
1851 return match_str;
1852 }
1853 }
1854 }
1855
1856 match_str = (char **) matchvec->index;
1857 vector_only_wrapper_free (matchvec);
1858 *status = CMD_COMPLETE_LIST_MATCH;
1859 return match_str;
1860}
1861
paulb92938a2002-12-13 21:20:42 +00001862char **
paul9ab68122003-01-18 01:16:20 +00001863cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001864{
1865 char **ret;
1866
1867 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1868 {
1869 enum node_type onode;
1870 vector shifted_vline;
1871 int index;
1872
1873 onode = vty->node;
1874 vty->node = ENABLE_NODE;
1875 /* We can try it on enable node, cos' the vty is authenticated */
1876
1877 shifted_vline = vector_init (vector_count(vline));
1878 /* use memcpy? */
1879 for (index = 1; index < vector_max (vline); index++)
1880 {
1881 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1882 }
1883
1884 ret = cmd_complete_command_real (shifted_vline, vty, status);
1885
1886 vector_free(shifted_vline);
1887 vty->node = onode;
1888 return ret;
1889 }
1890
1891
1892 return cmd_complete_command_real (vline, vty, status);
1893}
1894
1895/* return parent node */
1896/* MUST eventually converge on CONFIG_NODE */
1897enum node_type node_parent ( enum node_type node )
1898{
1899 enum node_type ret;
1900
paul9ab68122003-01-18 01:16:20 +00001901 assert (node > CONFIG_NODE);
1902
1903 switch (node)
1904 {
1905 case BGP_VPNV4_NODE:
1906 case BGP_IPV4_NODE:
1907 case BGP_IPV4M_NODE:
1908 case BGP_IPV6_NODE:
1909 ret = BGP_NODE;
1910 break;
1911 case KEYCHAIN_KEY_NODE:
1912 ret = KEYCHAIN_NODE;
1913 break;
1914 default:
1915 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001916 }
1917
1918 return ret;
1919}
1920
paul718e3742002-12-13 20:15:29 +00001921/* Execute command by argument vline vector. */
1922int
paulb92938a2002-12-13 21:20:42 +00001923cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001924{
1925 int i;
1926 int index;
1927 vector cmd_vector;
1928 struct cmd_element *cmd_element;
1929 struct cmd_element *matched_element;
1930 unsigned int matched_count, incomplete_count;
1931 int argc;
1932 char *argv[CMD_ARGC_MAX];
1933 enum match_type match = 0;
1934 int varflag;
1935 char *command;
1936
1937 /* Make copy of command elements. */
1938 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1939
1940 for (index = 0; index < vector_max (vline); index++)
1941 {
1942 int ret;
1943
1944 command = vector_slot (vline, index);
1945
1946 match = cmd_filter_by_completion (command, cmd_vector, index);
1947
1948 if (match == vararg_match)
1949 break;
1950
1951 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1952
1953 if (ret == 1)
1954 {
1955 vector_free (cmd_vector);
1956 return CMD_ERR_AMBIGUOUS;
1957 }
1958 else if (ret == 2)
1959 {
1960 vector_free (cmd_vector);
1961 return CMD_ERR_NO_MATCH;
1962 }
1963 }
1964
1965 /* Check matched count. */
1966 matched_element = NULL;
1967 matched_count = 0;
1968 incomplete_count = 0;
1969
1970 for (i = 0; i < vector_max (cmd_vector); i++)
1971 if (vector_slot (cmd_vector,i) != NULL)
1972 {
1973 cmd_element = vector_slot (cmd_vector,i);
1974
1975 if (match == vararg_match || index >= cmd_element->cmdsize)
1976 {
1977 matched_element = cmd_element;
1978#if 0
1979 printf ("DEBUG: %s\n", cmd_element->string);
1980#endif
1981 matched_count++;
1982 }
1983 else
1984 {
1985 incomplete_count++;
1986 }
1987 }
1988
1989 /* Finish of using cmd_vector. */
1990 vector_free (cmd_vector);
1991
1992 /* To execute command, matched_count must be 1.*/
1993 if (matched_count == 0)
1994 {
1995 if (incomplete_count)
1996 return CMD_ERR_INCOMPLETE;
1997 else
1998 return CMD_ERR_NO_MATCH;
1999 }
2000
2001 if (matched_count > 1)
2002 return CMD_ERR_AMBIGUOUS;
2003
2004 /* Argument treatment */
2005 varflag = 0;
2006 argc = 0;
2007
2008 for (i = 0; i < vector_max (vline); i++)
2009 {
2010 if (varflag)
2011 argv[argc++] = vector_slot (vline, i);
2012 else
2013 {
2014 vector descvec = vector_slot (matched_element->strvec, i);
2015
2016 if (vector_max (descvec) == 1)
2017 {
2018 struct desc *desc = vector_slot (descvec, 0);
2019 char *str = desc->cmd;
2020
2021 if (CMD_VARARG (str))
2022 varflag = 1;
2023
2024 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
2025 argv[argc++] = vector_slot (vline, i);
2026 }
2027 else
2028 argv[argc++] = vector_slot (vline, i);
2029 }
2030
2031 if (argc >= CMD_ARGC_MAX)
2032 return CMD_ERR_EXEED_ARGC_MAX;
2033 }
2034
2035 /* For vtysh execution. */
2036 if (cmd)
2037 *cmd = matched_element;
2038
2039 if (matched_element->daemon)
2040 return CMD_SUCCESS_DAEMON;
2041
2042 /* Execute matched command. */
2043 return (*matched_element->func) (matched_element, vty, argc, argv);
2044}
2045
paulb92938a2002-12-13 21:20:42 +00002046
2047int
2048cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
paul9ab68122003-01-18 01:16:20 +00002049 int ret, saved_ret, tried = 0;
2050 enum node_type onode, try_node;
2051
2052 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002053
2054 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2055 {
2056 vector shifted_vline;
2057 int index;
2058
2059 vty->node = ENABLE_NODE;
2060 /* We can try it on enable node, cos' the vty is authenticated */
2061
2062 shifted_vline = vector_init (vector_count(vline));
2063 /* use memcpy? */
2064 for (index = 1; index < vector_max (vline); index++)
2065 {
2066 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2067 }
2068
2069 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2070
2071 vector_free(shifted_vline);
2072 vty->node = onode;
2073 return ret;
2074 }
2075
2076
paul9ab68122003-01-18 01:16:20 +00002077 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002078
2079 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002080 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002081 && vty->node > CONFIG_NODE )
2082 {
paul9ab68122003-01-18 01:16:20 +00002083 try_node = node_parent(try_node);
2084 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002085 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002086 tried = 1;
2087 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002088 {
paul9ab68122003-01-18 01:16:20 +00002089 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002090 return ret;
2091 }
paulb92938a2002-12-13 21:20:42 +00002092 }
paul9ab68122003-01-18 01:16:20 +00002093 /* no command succeeded, reset the vty to the original node and
2094 return the error for this node */
2095 if ( tried )
2096 vty->node = onode;
2097 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002098}
2099
paul718e3742002-12-13 20:15:29 +00002100/* Execute command by argument readline. */
2101int
2102cmd_execute_command_strict (vector vline, struct vty *vty,
2103 struct cmd_element **cmd)
2104{
2105 int i;
2106 int index;
2107 vector cmd_vector;
2108 struct cmd_element *cmd_element;
2109 struct cmd_element *matched_element;
2110 unsigned int matched_count, incomplete_count;
2111 int argc;
2112 char *argv[CMD_ARGC_MAX];
2113 int varflag;
2114 enum match_type match = 0;
2115 char *command;
2116
2117 /* Make copy of command element */
2118 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2119
2120 for (index = 0; index < vector_max (vline); index++)
2121 {
2122 int ret;
2123
2124 command = vector_slot (vline, index);
2125
2126 match = cmd_filter_by_string (vector_slot (vline, index),
2127 cmd_vector, index);
2128
2129 /* If command meets '.VARARG' then finish matching. */
2130 if (match == vararg_match)
2131 break;
2132
2133 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2134 if (ret == 1)
2135 {
2136 vector_free (cmd_vector);
2137 return CMD_ERR_AMBIGUOUS;
2138 }
2139 if (ret == 2)
2140 {
2141 vector_free (cmd_vector);
2142 return CMD_ERR_NO_MATCH;
2143 }
2144 }
2145
2146 /* Check matched count. */
2147 matched_element = NULL;
2148 matched_count = 0;
2149 incomplete_count = 0;
2150 for (i = 0; i < vector_max (cmd_vector); i++)
2151 if (vector_slot (cmd_vector,i) != NULL)
2152 {
2153 cmd_element = vector_slot (cmd_vector,i);
2154
2155 if (match == vararg_match || index >= cmd_element->cmdsize)
2156 {
2157 matched_element = cmd_element;
2158 matched_count++;
2159 }
2160 else
2161 incomplete_count++;
2162 }
2163
2164 /* Finish of using cmd_vector. */
2165 vector_free (cmd_vector);
2166
2167 /* To execute command, matched_count must be 1.*/
2168 if (matched_count == 0)
2169 {
2170 if (incomplete_count)
2171 return CMD_ERR_INCOMPLETE;
2172 else
2173 return CMD_ERR_NO_MATCH;
2174 }
2175
2176 if (matched_count > 1)
2177 return CMD_ERR_AMBIGUOUS;
2178
2179 /* Argument treatment */
2180 varflag = 0;
2181 argc = 0;
2182
2183 for (i = 0; i < vector_max (vline); i++)
2184 {
2185 if (varflag)
2186 argv[argc++] = vector_slot (vline, i);
2187 else
2188 {
2189 vector descvec = vector_slot (matched_element->strvec, i);
2190
2191 if (vector_max (descvec) == 1)
2192 {
2193 struct desc *desc = vector_slot (descvec, 0);
2194 char *str = desc->cmd;
2195
2196 if (CMD_VARARG (str))
2197 varflag = 1;
2198
2199 if (varflag || CMD_VARIABLE (str) || CMD_OPTION (str))
2200 argv[argc++] = vector_slot (vline, i);
2201 }
2202 else
2203 argv[argc++] = vector_slot (vline, i);
2204 }
2205
2206 if (argc >= CMD_ARGC_MAX)
2207 return CMD_ERR_EXEED_ARGC_MAX;
2208 }
2209
2210 /* For vtysh execution. */
2211 if (cmd)
2212 *cmd = matched_element;
2213
2214 if (matched_element->daemon)
2215 return CMD_SUCCESS_DAEMON;
2216
2217 /* Now execute matched command */
2218 return (*matched_element->func) (matched_element, vty, argc, argv);
2219}
2220
2221/* Configration make from file. */
2222int
2223config_from_file (struct vty *vty, FILE *fp)
2224{
2225 int ret;
2226 vector vline;
2227
2228 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2229 {
2230 vline = cmd_make_strvec (vty->buf);
2231
2232 /* In case of comment line */
2233 if (vline == NULL)
2234 continue;
2235 /* Execute configuration command : this is strict match */
2236 ret = cmd_execute_command_strict (vline, vty, NULL);
2237
2238 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002239 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2240 && vty->node != CONFIG_NODE)
paul9ab68122003-01-18 01:16:20 +00002241 {
paulb92938a2002-12-13 21:20:42 +00002242 vty->node = node_parent(vty->node);
paul9ab68122003-01-18 01:16:20 +00002243 ret = cmd_execute_command_strict (vline, vty, NULL);
2244 }
2245
paul718e3742002-12-13 20:15:29 +00002246 cmd_free_strvec (vline);
2247
2248 if (ret != CMD_SUCCESS && ret != CMD_WARNING)
2249 return ret;
2250 }
2251 return CMD_SUCCESS;
2252}
2253
2254/* Configration from terminal */
2255DEFUN (config_terminal,
2256 config_terminal_cmd,
2257 "configure terminal",
2258 "Configuration from vty interface\n"
2259 "Configuration terminal\n")
2260{
2261 if (vty_config_lock (vty))
2262 vty->node = CONFIG_NODE;
2263 else
2264 {
2265 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2266 return CMD_WARNING;
2267 }
2268 return CMD_SUCCESS;
2269}
2270
2271/* Enable command */
2272DEFUN (enable,
2273 config_enable_cmd,
2274 "enable",
2275 "Turn on privileged mode command\n")
2276{
2277 /* If enable password is NULL, change to ENABLE_NODE */
2278 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2279 vty->type == VTY_SHELL_SERV)
2280 vty->node = ENABLE_NODE;
2281 else
2282 vty->node = AUTH_ENABLE_NODE;
2283
2284 return CMD_SUCCESS;
2285}
2286
2287/* Disable command */
2288DEFUN (disable,
2289 config_disable_cmd,
2290 "disable",
2291 "Turn off privileged mode command\n")
2292{
2293 if (vty->node == ENABLE_NODE)
2294 vty->node = VIEW_NODE;
2295 return CMD_SUCCESS;
2296}
2297
2298/* Down vty node level. */
2299DEFUN (config_exit,
2300 config_exit_cmd,
2301 "exit",
2302 "Exit current mode and down to previous mode\n")
2303{
2304 switch (vty->node)
2305 {
2306 case VIEW_NODE:
2307 case ENABLE_NODE:
2308 if (vty_shell (vty))
2309 exit (0);
2310 else
2311 vty->status = VTY_CLOSE;
2312 break;
2313 case CONFIG_NODE:
2314 vty->node = ENABLE_NODE;
2315 vty_config_unlock (vty);
2316 break;
2317 case INTERFACE_NODE:
2318 case ZEBRA_NODE:
2319 case BGP_NODE:
2320 case RIP_NODE:
2321 case RIPNG_NODE:
2322 case OSPF_NODE:
2323 case OSPF6_NODE:
2324 case KEYCHAIN_NODE:
2325 case MASC_NODE:
2326 case RMAP_NODE:
2327 case VTY_NODE:
2328 vty->node = CONFIG_NODE;
2329 break;
2330 case BGP_VPNV4_NODE:
2331 case BGP_IPV4_NODE:
2332 case BGP_IPV4M_NODE:
2333 case BGP_IPV6_NODE:
2334 vty->node = BGP_NODE;
2335 break;
2336 case KEYCHAIN_KEY_NODE:
2337 vty->node = KEYCHAIN_NODE;
2338 break;
2339 default:
2340 break;
2341 }
2342 return CMD_SUCCESS;
2343}
2344
2345/* quit is alias of exit. */
2346ALIAS (config_exit,
2347 config_quit_cmd,
2348 "quit",
2349 "Exit current mode and down to previous mode\n")
2350
2351/* End of configuration. */
2352DEFUN (config_end,
2353 config_end_cmd,
2354 "end",
2355 "End current mode and change to enable mode.")
2356{
2357 switch (vty->node)
2358 {
2359 case VIEW_NODE:
2360 case ENABLE_NODE:
2361 /* Nothing to do. */
2362 break;
2363 case CONFIG_NODE:
2364 case INTERFACE_NODE:
2365 case ZEBRA_NODE:
2366 case RIP_NODE:
2367 case RIPNG_NODE:
2368 case BGP_NODE:
2369 case BGP_VPNV4_NODE:
2370 case BGP_IPV4_NODE:
2371 case BGP_IPV4M_NODE:
2372 case BGP_IPV6_NODE:
2373 case RMAP_NODE:
2374 case OSPF_NODE:
2375 case OSPF6_NODE:
2376 case KEYCHAIN_NODE:
2377 case KEYCHAIN_KEY_NODE:
2378 case MASC_NODE:
2379 case VTY_NODE:
2380 vty_config_unlock (vty);
2381 vty->node = ENABLE_NODE;
2382 break;
2383 default:
2384 break;
2385 }
2386 return CMD_SUCCESS;
2387}
2388
2389/* Show version. */
2390DEFUN (show_version,
2391 show_version_cmd,
2392 "show version",
2393 SHOW_STR
2394 "Displays zebra version\n")
2395{
paule8f29842003-08-12 13:08:31 +00002396 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION,
paul718e3742002-12-13 20:15:29 +00002397 host_name,
2398 VTY_NEWLINE);
2399 vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
2400
2401 return CMD_SUCCESS;
2402}
2403
2404/* Help display function for all node. */
2405DEFUN (config_help,
2406 config_help_cmd,
2407 "help",
2408 "Description of the interactive help system\n")
2409{
2410 vty_out (vty,
2411 "Zebra VTY provides advanced help feature. When you need help,%s\
2412anytime at the command line please press '?'.%s\
2413%s\
2414If nothing matches, the help list will be empty and you must backup%s\
2415 until entering a '?' shows the available options.%s\
2416Two styles of help are provided:%s\
24171. Full help is available when you are ready to enter a%s\
2418command argument (e.g. 'show ?') and describes each possible%s\
2419argument.%s\
24202. Partial help is provided when an abbreviated argument is entered%s\
2421 and you want to know what arguments match the input%s\
2422 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2423 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2424 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2425 return CMD_SUCCESS;
2426}
2427
2428/* Help display function for all node. */
2429DEFUN (config_list,
2430 config_list_cmd,
2431 "list",
2432 "Print command list\n")
2433{
2434 int i;
2435 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2436 struct cmd_element *cmd;
2437
2438 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2439 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2440 vty_out (vty, " %s%s", cmd->string,
2441 VTY_NEWLINE);
2442 return CMD_SUCCESS;
2443}
2444
2445/* Write current configuration into file. */
2446DEFUN (config_write_file,
2447 config_write_file_cmd,
2448 "write file",
2449 "Write running configuration to memory, network, or terminal\n"
2450 "Write to configuration file\n")
2451{
2452 int i;
2453 int fd;
2454 struct cmd_node *node;
2455 char *config_file;
2456 char *config_file_tmp = NULL;
2457 char *config_file_sav = NULL;
2458 struct vty *file_vty;
2459
2460 /* Check and see if we are operating under vtysh configuration */
2461 if (host.config == NULL)
2462 {
2463 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2464 VTY_NEWLINE);
2465 return CMD_WARNING;
2466 }
2467
2468 /* Get filename. */
2469 config_file = host.config;
2470
2471 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2472 strcpy (config_file_sav, config_file);
2473 strcat (config_file_sav, CONF_BACKUP_EXT);
2474
2475
2476 config_file_tmp = malloc (strlen (config_file) + 8);
2477 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2478
2479 /* Open file to configuration write. */
2480 fd = mkstemp (config_file_tmp);
2481 if (fd < 0)
2482 {
2483 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2484 VTY_NEWLINE);
2485 free (config_file_tmp);
2486 free (config_file_sav);
2487 return CMD_WARNING;
2488 }
2489
2490 /* Make vty for configuration file. */
2491 file_vty = vty_new ();
2492 file_vty->fd = fd;
2493 file_vty->type = VTY_FILE;
2494
2495 /* Config file header print. */
2496 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2497 vty_time_print (file_vty, 1);
2498 vty_out (file_vty, "!\n");
2499
2500 for (i = 0; i < vector_max (cmdvec); i++)
2501 if ((node = vector_slot (cmdvec, i)) && node->func)
2502 {
2503 if ((*node->func) (file_vty))
2504 vty_out (file_vty, "!\n");
2505 }
2506 vty_close (file_vty);
2507
2508 if (unlink (config_file_sav) != 0)
2509 if (errno != ENOENT)
2510 {
2511 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2512 VTY_NEWLINE);
2513 free (config_file_sav);
2514 free (config_file_tmp);
2515 unlink (config_file_tmp);
2516 return CMD_WARNING;
2517 }
2518 if (link (config_file, config_file_sav) != 0)
2519 {
2520 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2521 VTY_NEWLINE);
2522 free (config_file_sav);
2523 free (config_file_tmp);
2524 unlink (config_file_tmp);
2525 return CMD_WARNING;
2526 }
2527 sync ();
2528 if (unlink (config_file) != 0)
2529 {
2530 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2531 VTY_NEWLINE);
2532 free (config_file_sav);
2533 free (config_file_tmp);
2534 unlink (config_file_tmp);
2535 return CMD_WARNING;
2536 }
2537 if (link (config_file_tmp, config_file) != 0)
2538 {
2539 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2540 VTY_NEWLINE);
2541 free (config_file_sav);
2542 free (config_file_tmp);
2543 unlink (config_file_tmp);
2544 return CMD_WARNING;
2545 }
2546 unlink (config_file_tmp);
2547 sync ();
2548
2549 free (config_file_sav);
2550 free (config_file_tmp);
2551 vty_out (vty, "Configuration saved to %s%s", config_file,
2552 VTY_NEWLINE);
2553 return CMD_SUCCESS;
2554}
2555
2556ALIAS (config_write_file,
2557 config_write_cmd,
2558 "write",
2559 "Write running configuration to memory, network, or terminal\n")
2560
2561ALIAS (config_write_file,
2562 config_write_memory_cmd,
2563 "write memory",
2564 "Write running configuration to memory, network, or terminal\n"
2565 "Write configuration to the file (same as write file)\n")
2566
2567ALIAS (config_write_file,
2568 copy_runningconfig_startupconfig_cmd,
2569 "copy running-config startup-config",
2570 "Copy configuration\n"
2571 "Copy running config to... \n"
2572 "Copy running config to startup config (same as write file)\n")
2573
2574/* Write current configuration into the terminal. */
2575DEFUN (config_write_terminal,
2576 config_write_terminal_cmd,
2577 "write terminal",
2578 "Write running configuration to memory, network, or terminal\n"
2579 "Write to terminal\n")
2580{
2581 int i;
2582 struct cmd_node *node;
2583
2584 if (vty->type == VTY_SHELL_SERV)
2585 {
2586 for (i = 0; i < vector_max (cmdvec); i++)
2587 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2588 {
2589 if ((*node->func) (vty))
2590 vty_out (vty, "!%s", VTY_NEWLINE);
2591 }
2592 }
2593 else
2594 {
2595 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2596 VTY_NEWLINE);
2597 vty_out (vty, "!%s", VTY_NEWLINE);
2598
2599 for (i = 0; i < vector_max (cmdvec); i++)
2600 if ((node = vector_slot (cmdvec, i)) && node->func)
2601 {
2602 if ((*node->func) (vty))
2603 vty_out (vty, "!%s", VTY_NEWLINE);
2604 }
2605 vty_out (vty, "end%s",VTY_NEWLINE);
2606 }
2607 return CMD_SUCCESS;
2608}
2609
2610/* Write current configuration into the terminal. */
2611ALIAS (config_write_terminal,
2612 show_running_config_cmd,
2613 "show running-config",
2614 SHOW_STR
2615 "running configuration\n")
2616
2617/* Write startup configuration into the terminal. */
2618DEFUN (show_startup_config,
2619 show_startup_config_cmd,
2620 "show startup-config",
2621 SHOW_STR
2622 "Contentes of startup configuration\n")
2623{
2624 char buf[BUFSIZ];
2625 FILE *confp;
2626
2627 confp = fopen (host.config, "r");
2628 if (confp == NULL)
2629 {
2630 vty_out (vty, "Can't open configuration file [%s]%s",
2631 host.config, VTY_NEWLINE);
2632 return CMD_WARNING;
2633 }
2634
2635 while (fgets (buf, BUFSIZ, confp))
2636 {
2637 char *cp = buf;
2638
2639 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2640 cp++;
2641 *cp = '\0';
2642
2643 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2644 }
2645
2646 fclose (confp);
2647
2648 return CMD_SUCCESS;
2649}
2650
2651/* Hostname configuration */
2652DEFUN (config_hostname,
2653 hostname_cmd,
2654 "hostname WORD",
2655 "Set system's network name\n"
2656 "This system's network name\n")
2657{
2658 if (!isalpha((int) *argv[0]))
2659 {
2660 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2661 return CMD_WARNING;
2662 }
2663
2664 if (host.name)
2665 XFREE (0, host.name);
2666
2667 host.name = strdup (argv[0]);
2668 return CMD_SUCCESS;
2669}
2670
2671DEFUN (config_no_hostname,
2672 no_hostname_cmd,
2673 "no hostname [HOSTNAME]",
2674 NO_STR
2675 "Reset system's network name\n"
2676 "Host name of this router\n")
2677{
2678 if (host.name)
2679 XFREE (0, host.name);
2680 host.name = NULL;
2681 return CMD_SUCCESS;
2682}
2683
2684/* VTY interface password set. */
2685DEFUN (config_password, password_cmd,
2686 "password (8|) WORD",
2687 "Assign the terminal connection password\n"
2688 "Specifies a HIDDEN password will follow\n"
2689 "dummy string \n"
2690 "The HIDDEN line password string\n")
2691{
2692 /* Argument check. */
2693 if (argc == 0)
2694 {
2695 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2696 return CMD_WARNING;
2697 }
2698
2699 if (argc == 2)
2700 {
2701 if (*argv[0] == '8')
2702 {
2703 if (host.password)
2704 XFREE (0, host.password);
2705 host.password = NULL;
2706 if (host.password_encrypt)
2707 XFREE (0, host.password_encrypt);
2708 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2709 return CMD_SUCCESS;
2710 }
2711 else
2712 {
2713 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2714 return CMD_WARNING;
2715 }
2716 }
2717
2718 if (!isalnum ((int) *argv[0]))
2719 {
2720 vty_out (vty,
2721 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2722 return CMD_WARNING;
2723 }
2724
2725 if (host.password)
2726 XFREE (0, host.password);
2727 host.password = NULL;
2728
2729 if (host.encrypt)
2730 {
2731 if (host.password_encrypt)
2732 XFREE (0, host.password_encrypt);
2733 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2734 }
2735 else
2736 host.password = XSTRDUP (0, argv[0]);
2737
2738 return CMD_SUCCESS;
2739}
2740
2741ALIAS (config_password, password_text_cmd,
2742 "password LINE",
2743 "Assign the terminal connection password\n"
2744 "The UNENCRYPTED (cleartext) line password\n")
2745
2746/* VTY enable password set. */
2747DEFUN (config_enable_password, enable_password_cmd,
2748 "enable password (8|) WORD",
2749 "Modify enable password parameters\n"
2750 "Assign the privileged level password\n"
2751 "Specifies a HIDDEN password will follow\n"
2752 "dummy string \n"
2753 "The HIDDEN 'enable' password string\n")
2754{
2755 /* Argument check. */
2756 if (argc == 0)
2757 {
2758 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2759 return CMD_WARNING;
2760 }
2761
2762 /* Crypt type is specified. */
2763 if (argc == 2)
2764 {
2765 if (*argv[0] == '8')
2766 {
2767 if (host.enable)
2768 XFREE (0, host.enable);
2769 host.enable = NULL;
2770
2771 if (host.enable_encrypt)
2772 XFREE (0, host.enable_encrypt);
2773 host.enable_encrypt = XSTRDUP (0, argv[1]);
2774
2775 return CMD_SUCCESS;
2776 }
2777 else
2778 {
2779 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2780 return CMD_WARNING;
2781 }
2782 }
2783
2784 if (!isalnum ((int) *argv[0]))
2785 {
2786 vty_out (vty,
2787 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2788 return CMD_WARNING;
2789 }
2790
2791 if (host.enable)
2792 XFREE (0, host.enable);
2793 host.enable = NULL;
2794
2795 /* Plain password input. */
2796 if (host.encrypt)
2797 {
2798 if (host.enable_encrypt)
2799 XFREE (0, host.enable_encrypt);
2800 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2801 }
2802 else
2803 host.enable = XSTRDUP (0, argv[0]);
2804
2805 return CMD_SUCCESS;
2806}
2807
2808ALIAS (config_enable_password,
2809 enable_password_text_cmd,
2810 "enable password LINE",
2811 "Modify enable password parameters\n"
2812 "Assign the privileged level password\n"
2813 "The UNENCRYPTED (cleartext) 'enable' password\n")
2814
2815/* VTY enable password delete. */
2816DEFUN (no_config_enable_password, no_enable_password_cmd,
2817 "no enable password",
2818 NO_STR
2819 "Modify enable password parameters\n"
2820 "Assign the privileged level password\n")
2821{
2822 if (host.enable)
2823 XFREE (0, host.enable);
2824 host.enable = NULL;
2825
2826 if (host.enable_encrypt)
2827 XFREE (0, host.enable_encrypt);
2828 host.enable_encrypt = NULL;
2829
2830 return CMD_SUCCESS;
2831}
2832
2833DEFUN (service_password_encrypt,
2834 service_password_encrypt_cmd,
2835 "service password-encryption",
2836 "Set up miscellaneous service\n"
2837 "Enable encrypted passwords\n")
2838{
2839 if (host.encrypt)
2840 return CMD_SUCCESS;
2841
2842 host.encrypt = 1;
2843
2844 if (host.password)
2845 {
2846 if (host.password_encrypt)
2847 XFREE (0, host.password_encrypt);
2848 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2849 }
2850 if (host.enable)
2851 {
2852 if (host.enable_encrypt)
2853 XFREE (0, host.enable_encrypt);
2854 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2855 }
2856
2857 return CMD_SUCCESS;
2858}
2859
2860DEFUN (no_service_password_encrypt,
2861 no_service_password_encrypt_cmd,
2862 "no service password-encryption",
2863 NO_STR
2864 "Set up miscellaneous service\n"
2865 "Enable encrypted passwords\n")
2866{
2867 if (! host.encrypt)
2868 return CMD_SUCCESS;
2869
2870 host.encrypt = 0;
2871
2872 if (host.password_encrypt)
2873 XFREE (0, host.password_encrypt);
2874 host.password_encrypt = NULL;
2875
2876 if (host.enable_encrypt)
2877 XFREE (0, host.enable_encrypt);
2878 host.enable_encrypt = NULL;
2879
2880 return CMD_SUCCESS;
2881}
2882
2883DEFUN (config_terminal_length, config_terminal_length_cmd,
2884 "terminal length <0-512>",
2885 "Set terminal line parameters\n"
2886 "Set number of lines on a screen\n"
2887 "Number of lines on screen (0 for no pausing)\n")
2888{
2889 int lines;
2890 char *endptr = NULL;
2891
2892 lines = strtol (argv[0], &endptr, 10);
2893 if (lines < 0 || lines > 512 || *endptr != '\0')
2894 {
2895 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2896 return CMD_WARNING;
2897 }
2898 vty->lines = lines;
2899
2900 return CMD_SUCCESS;
2901}
2902
2903DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2904 "terminal no length",
2905 "Set terminal line parameters\n"
2906 NO_STR
2907 "Set number of lines on a screen\n")
2908{
2909 vty->lines = -1;
2910 return CMD_SUCCESS;
2911}
2912
2913DEFUN (service_terminal_length, service_terminal_length_cmd,
2914 "service terminal-length <0-512>",
2915 "Set up miscellaneous service\n"
2916 "System wide terminal length configuration\n"
2917 "Number of lines of VTY (0 means no line control)\n")
2918{
2919 int lines;
2920 char *endptr = NULL;
2921
2922 lines = strtol (argv[0], &endptr, 10);
2923 if (lines < 0 || lines > 512 || *endptr != '\0')
2924 {
2925 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2926 return CMD_WARNING;
2927 }
2928 host.lines = lines;
2929
2930 return CMD_SUCCESS;
2931}
2932
2933DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2934 "no service terminal-length [<0-512>]",
2935 NO_STR
2936 "Set up miscellaneous service\n"
2937 "System wide terminal length configuration\n"
2938 "Number of lines of VTY (0 means no line control)\n")
2939{
2940 host.lines = -1;
2941 return CMD_SUCCESS;
2942}
2943
2944DEFUN (config_log_stdout,
2945 config_log_stdout_cmd,
2946 "log stdout",
2947 "Logging control\n"
2948 "Logging goes to stdout\n")
2949{
2950 zlog_set_flag (NULL, ZLOG_STDOUT);
2951 host.log_stdout = 1;
2952 return CMD_SUCCESS;
2953}
2954
2955DEFUN (no_config_log_stdout,
2956 no_config_log_stdout_cmd,
2957 "no log stdout",
2958 NO_STR
2959 "Logging control\n"
2960 "Cancel logging to stdout\n")
2961{
2962 zlog_reset_flag (NULL, ZLOG_STDOUT);
2963 host.log_stdout = 0;
2964 return CMD_SUCCESS;
2965}
2966
2967DEFUN (config_log_file,
2968 config_log_file_cmd,
2969 "log file FILENAME",
2970 "Logging control\n"
2971 "Logging to file\n"
2972 "Logging filename\n")
2973{
2974 int ret;
2975 char *cwd;
2976 char *fullpath;
2977
2978 /* Path detection. */
2979 if (! IS_DIRECTORY_SEP (*argv[0]))
2980 {
2981 cwd = getcwd (NULL, MAXPATHLEN);
2982 fullpath = XMALLOC (MTYPE_TMP,
2983 strlen (cwd) + strlen (argv[0]) + 2);
2984 sprintf (fullpath, "%s/%s", cwd, argv[0]);
2985 }
2986 else
2987 fullpath = argv[0];
2988
2989 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
2990
2991 if (!ret)
2992 {
2993 vty_out (vty, "can't open logfile %s\n", argv[0]);
2994 return CMD_WARNING;
2995 }
2996
2997 if (host.logfile)
2998 XFREE (MTYPE_TMP, host.logfile);
2999
3000 host.logfile = strdup (argv[0]);
3001
3002 return CMD_SUCCESS;
3003}
3004
3005DEFUN (no_config_log_file,
3006 no_config_log_file_cmd,
3007 "no log file [FILENAME]",
3008 NO_STR
3009 "Logging control\n"
3010 "Cancel logging to file\n"
3011 "Logging file name\n")
3012{
3013 zlog_reset_file (NULL);
3014
3015 if (host.logfile)
3016 XFREE (MTYPE_TMP, host.logfile);
3017
3018 host.logfile = NULL;
3019
3020 return CMD_SUCCESS;
3021}
3022
3023DEFUN (config_log_syslog,
3024 config_log_syslog_cmd,
3025 "log syslog",
3026 "Logging control\n"
3027 "Logging goes to syslog\n")
3028{
3029 zlog_set_flag (NULL, ZLOG_SYSLOG);
3030 host.log_syslog = 1;
paul12ab19f2003-07-26 06:14:55 +00003031 zlog_default->facility = LOG_DAEMON;
3032 return CMD_SUCCESS;
3033}
3034
3035DEFUN (config_log_syslog_facility,
3036 config_log_syslog_facility_cmd,
3037 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3038 "Logging control\n"
3039 "Logging goes to syslog\n"
3040 "Facility parameter for syslog messages\n"
3041 "Kernel\n"
3042 "User process\n"
3043 "Mail system\n"
3044 "System daemons\n"
3045 "Authorization system\n"
3046 "Syslog itself\n"
3047 "Line printer system\n"
3048 "USENET news\n"
3049 "Unix-to-Unix copy system\n"
3050 "Cron/at facility\n"
3051 "Local use\n"
3052 "Local use\n"
3053 "Local use\n"
3054 "Local use\n"
3055 "Local use\n"
3056 "Local use\n"
3057 "Local use\n"
3058 "Local use\n")
3059{
3060 int facility = LOG_DAEMON;
3061
3062 zlog_set_flag (NULL, ZLOG_SYSLOG);
3063 host.log_syslog = 1;
3064
3065 if (strncmp (argv[0], "kern", 1) == 0)
3066 facility = LOG_KERN;
3067 else if (strncmp (argv[0], "user", 2) == 0)
3068 facility = LOG_USER;
3069 else if (strncmp (argv[0], "mail", 1) == 0)
3070 facility = LOG_MAIL;
3071 else if (strncmp (argv[0], "daemon", 1) == 0)
3072 facility = LOG_DAEMON;
3073 else if (strncmp (argv[0], "auth", 1) == 0)
3074 facility = LOG_AUTH;
3075 else if (strncmp (argv[0], "syslog", 1) == 0)
3076 facility = LOG_SYSLOG;
3077 else if (strncmp (argv[0], "lpr", 2) == 0)
3078 facility = LOG_LPR;
3079 else if (strncmp (argv[0], "news", 1) == 0)
3080 facility = LOG_NEWS;
3081 else if (strncmp (argv[0], "uucp", 2) == 0)
3082 facility = LOG_UUCP;
3083 else if (strncmp (argv[0], "cron", 1) == 0)
3084 facility = LOG_CRON;
3085 else if (strncmp (argv[0], "local0", 6) == 0)
3086 facility = LOG_LOCAL0;
3087 else if (strncmp (argv[0], "local1", 6) == 0)
3088 facility = LOG_LOCAL1;
3089 else if (strncmp (argv[0], "local2", 6) == 0)
3090 facility = LOG_LOCAL2;
3091 else if (strncmp (argv[0], "local3", 6) == 0)
3092 facility = LOG_LOCAL3;
3093 else if (strncmp (argv[0], "local4", 6) == 0)
3094 facility = LOG_LOCAL4;
3095 else if (strncmp (argv[0], "local5", 6) == 0)
3096 facility = LOG_LOCAL5;
3097 else if (strncmp (argv[0], "local6", 6) == 0)
3098 facility = LOG_LOCAL6;
3099 else if (strncmp (argv[0], "local7", 6) == 0)
3100 facility = LOG_LOCAL7;
3101
3102 zlog_default->facility = facility;
3103
paul718e3742002-12-13 20:15:29 +00003104 return CMD_SUCCESS;
3105}
3106
3107DEFUN (no_config_log_syslog,
3108 no_config_log_syslog_cmd,
3109 "no log syslog",
3110 NO_STR
3111 "Logging control\n"
3112 "Cancel logging to syslog\n")
3113{
3114 zlog_reset_flag (NULL, ZLOG_SYSLOG);
3115 host.log_syslog = 0;
paul12ab19f2003-07-26 06:14:55 +00003116 zlog_default->facility = LOG_DAEMON;
paul718e3742002-12-13 20:15:29 +00003117 return CMD_SUCCESS;
3118}
3119
paul12ab19f2003-07-26 06:14:55 +00003120ALIAS (no_config_log_syslog,
3121 no_config_log_syslog_facility_cmd,
3122 "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3123 NO_STR
3124 "Logging control\n"
3125 "Logging goes to syslog\n"
3126 "Facility parameter for syslog messages\n"
3127 "Kernel\n"
3128 "User process\n"
3129 "Mail system\n"
3130 "System daemons\n"
3131 "Authorization system\n"
3132 "Syslog itself\n"
3133 "Line printer system\n"
3134 "USENET news\n"
3135 "Unix-to-Unix copy system\n"
3136 "Cron/at facility\n"
3137 "Local use\n"
3138 "Local use\n"
3139 "Local use\n"
3140 "Local use\n"
3141 "Local use\n"
3142 "Local use\n"
3143 "Local use\n"
3144 "Local use\n")
3145
paul718e3742002-12-13 20:15:29 +00003146DEFUN (config_log_trap,
3147 config_log_trap_cmd,
3148 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3149 "Logging control\n"
3150 "Limit logging to specifed level\n")
3151{
3152 int new_level ;
3153
3154 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
3155 {
3156 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
3157 /* found new logging level */
3158 {
3159 zlog_default->maskpri = new_level;
3160 return CMD_SUCCESS;
3161 }
3162 }
3163 return CMD_ERR_NO_MATCH;
3164}
3165
3166DEFUN (no_config_log_trap,
3167 no_config_log_trap_cmd,
3168 "no log trap",
3169 NO_STR
3170 "Logging control\n"
3171 "Permit all logging information\n")
3172{
3173 zlog_default->maskpri = LOG_DEBUG;
3174 return CMD_SUCCESS;
3175}
3176
3177DEFUN (config_log_record_priority,
3178 config_log_record_priority_cmd,
3179 "log record-priority",
3180 "Logging control\n"
3181 "Log the priority of the message within the message\n")
3182{
3183 zlog_default->record_priority = 1 ;
3184 return CMD_SUCCESS;
3185}
3186
3187DEFUN (no_config_log_record_priority,
3188 no_config_log_record_priority_cmd,
3189 "no log record-priority",
3190 NO_STR
3191 "Logging control\n"
3192 "Do not log the priority of the message within the message\n")
3193{
3194 zlog_default->record_priority = 0 ;
3195 return CMD_SUCCESS;
3196}
3197
3198
3199DEFUN (banner_motd_default,
3200 banner_motd_default_cmd,
3201 "banner motd default",
3202 "Set banner string\n"
3203 "Strings for motd\n"
3204 "Default string\n")
3205{
3206 host.motd = default_motd;
3207 return CMD_SUCCESS;
3208}
3209
3210DEFUN (no_banner_motd,
3211 no_banner_motd_cmd,
3212 "no banner motd",
3213 NO_STR
3214 "Set banner string\n"
3215 "Strings for motd\n")
3216{
3217 host.motd = NULL;
3218 return CMD_SUCCESS;
3219}
3220
3221/* Set config filename. Called from vty.c */
3222void
3223host_config_set (char *filename)
3224{
3225 host.config = strdup (filename);
3226}
3227
3228void
3229install_default (enum node_type node)
3230{
3231 install_element (node, &config_exit_cmd);
3232 install_element (node, &config_quit_cmd);
3233 install_element (node, &config_end_cmd);
3234 install_element (node, &config_help_cmd);
3235 install_element (node, &config_list_cmd);
3236
3237 install_element (node, &config_write_terminal_cmd);
3238 install_element (node, &config_write_file_cmd);
3239 install_element (node, &config_write_memory_cmd);
3240 install_element (node, &config_write_cmd);
3241 install_element (node, &show_running_config_cmd);
3242}
3243
3244/* Initialize command interface. Install basic nodes and commands. */
3245void
3246cmd_init (int terminal)
3247{
3248 /* Allocate initial top vector of commands. */
3249 cmdvec = vector_init (VECTOR_MIN_SIZE);
3250
3251 /* Default host value settings. */
3252 host.name = NULL;
3253 host.password = NULL;
3254 host.enable = NULL;
3255 host.logfile = NULL;
3256 host.config = NULL;
3257 host.lines = -1;
3258 host.motd = default_motd;
3259
3260 /* Install top nodes. */
3261 install_node (&view_node, NULL);
3262 install_node (&enable_node, NULL);
3263 install_node (&auth_node, NULL);
3264 install_node (&auth_enable_node, NULL);
3265 install_node (&config_node, config_write_host);
3266
3267 /* Each node's basic commands. */
3268 install_element (VIEW_NODE, &show_version_cmd);
3269 if (terminal)
3270 {
3271 install_element (VIEW_NODE, &config_list_cmd);
3272 install_element (VIEW_NODE, &config_exit_cmd);
3273 install_element (VIEW_NODE, &config_quit_cmd);
3274 install_element (VIEW_NODE, &config_help_cmd);
3275 install_element (VIEW_NODE, &config_enable_cmd);
3276 install_element (VIEW_NODE, &config_terminal_length_cmd);
3277 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3278 }
3279
3280 if (terminal)
3281 {
3282 install_default (ENABLE_NODE);
3283 install_element (ENABLE_NODE, &config_disable_cmd);
3284 install_element (ENABLE_NODE, &config_terminal_cmd);
3285 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3286 }
3287 install_element (ENABLE_NODE, &show_startup_config_cmd);
3288 install_element (ENABLE_NODE, &show_version_cmd);
3289 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3290 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3291
3292 if (terminal)
3293 install_default (CONFIG_NODE);
3294 install_element (CONFIG_NODE, &hostname_cmd);
3295 install_element (CONFIG_NODE, &no_hostname_cmd);
3296 install_element (CONFIG_NODE, &password_cmd);
3297 install_element (CONFIG_NODE, &password_text_cmd);
3298 install_element (CONFIG_NODE, &enable_password_cmd);
3299 install_element (CONFIG_NODE, &enable_password_text_cmd);
3300 install_element (CONFIG_NODE, &no_enable_password_cmd);
3301 if (terminal)
3302 {
3303 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3304 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3305 install_element (CONFIG_NODE, &config_log_file_cmd);
3306 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3307 install_element (CONFIG_NODE, &config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003308 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003309 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003310 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003311 install_element (CONFIG_NODE, &config_log_trap_cmd);
3312 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3313 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3314 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3315 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3316 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3317 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3318 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3319 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3320 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3321 }
3322
paul9ab68122003-01-18 01:16:20 +00003323 if (terminal)
3324 {
3325 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3326 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3327 }
paul718e3742002-12-13 20:15:29 +00003328 srand(time(NULL));
3329}