blob: 8c60fc4f05a7626641b532980d64b487f174c222 [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;
paul54aba542003-08-21 20:28:24 +00001532 int ret;
1533 enum match_type match;
1534 char *command;
paul718e3742002-12-13 20:15:29 +00001535 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. */
paul54aba542003-08-21 20:28:24 +00001547 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001548 for (i = 0; i < index; i++)
1549 {
paul718e3742002-12-13 20:15:29 +00001550 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00001551 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);
paul718e3742002-12-13 20:15:29 +00001572 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
paul54aba542003-08-21 20:28:24 +00001594 /* 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
paul718e3742002-12-13 20:15:29 +00001599 /* 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
paul54aba542003-08-21 20:28:24 +00001606 /* if command is NULL, index may be equal to vector_max */
1607 if (command && index >= vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001608 vector_slot (cmd_vector, i) = NULL;
1609 else
1610 {
paul54aba542003-08-21 20:28:24 +00001611 /* Check if command is completed. */
1612 if (command == NULL && index == vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001613 {
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);
paul54aba542003-08-21 20:28:24 +00001627 string = cmd_entry_function_desc (command, desc->cmd);
paul718e3742002-12-13 20:15:29 +00001628 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
paulb92938a2002-12-13 21:20:42 +00001651vector
1652cmd_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
paul718e3742002-12-13 20:15:29 +00001685/* Check LCD of matched command. */
1686int
1687cmd_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. */
1719char **
paulb92938a2002-12-13 21:20:42 +00001720cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001721{
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
paulb92938a2002-12-13 21:20:42 +00001866char **
paul9ab68122003-01-18 01:16:20 +00001867cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001868{
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 */
1901enum node_type node_parent ( enum node_type node )
1902{
1903 enum node_type ret;
1904
paul9ab68122003-01-18 01:16:20 +00001905 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;
paulb92938a2002-12-13 21:20:42 +00001920 }
1921
1922 return ret;
1923}
1924
paul718e3742002-12-13 20:15:29 +00001925/* Execute command by argument vline vector. */
1926int
paulb92938a2002-12-13 21:20:42 +00001927cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001928{
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
paulb92938a2002-12-13 21:20:42 +00002050
2051int
2052cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
paul9ab68122003-01-18 01:16:20 +00002053 int ret, saved_ret, tried = 0;
2054 enum node_type onode, try_node;
2055
2056 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002057
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
paul9ab68122003-01-18 01:16:20 +00002081 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002082
2083 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002084 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002085 && vty->node > CONFIG_NODE )
2086 {
paul9ab68122003-01-18 01:16:20 +00002087 try_node = node_parent(try_node);
2088 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002089 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002090 tried = 1;
2091 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002092 {
paul9ab68122003-01-18 01:16:20 +00002093 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002094 return ret;
2095 }
paulb92938a2002-12-13 21:20:42 +00002096 }
paul9ab68122003-01-18 01:16:20 +00002097 /* 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;
pauleda031f2003-01-18 00:39:19 +00002102}
2103
paul718e3742002-12-13 20:15:29 +00002104/* Execute command by argument readline. */
2105int
2106cmd_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. */
2226int
2227config_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 */
paulb92938a2002-12-13 21:20:42 +00002243 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2244 && vty->node != CONFIG_NODE)
paul9ab68122003-01-18 01:16:20 +00002245 {
paulb92938a2002-12-13 21:20:42 +00002246 vty->node = node_parent(vty->node);
paul9ab68122003-01-18 01:16:20 +00002247 ret = cmd_execute_command_strict (vline, vty, NULL);
2248 }
2249
paul718e3742002-12-13 20:15:29 +00002250 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 */
2259DEFUN (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 */
2276DEFUN (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 */
2292DEFUN (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. */
2303DEFUN (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 KEYCHAIN_NODE:
2329 case MASC_NODE:
2330 case RMAP_NODE:
2331 case VTY_NODE:
2332 vty->node = CONFIG_NODE;
2333 break;
2334 case BGP_VPNV4_NODE:
2335 case BGP_IPV4_NODE:
2336 case BGP_IPV4M_NODE:
2337 case BGP_IPV6_NODE:
2338 vty->node = BGP_NODE;
2339 break;
2340 case KEYCHAIN_KEY_NODE:
2341 vty->node = KEYCHAIN_NODE;
2342 break;
2343 default:
2344 break;
2345 }
2346 return CMD_SUCCESS;
2347}
2348
2349/* quit is alias of exit. */
2350ALIAS (config_exit,
2351 config_quit_cmd,
2352 "quit",
2353 "Exit current mode and down to previous mode\n")
2354
2355/* End of configuration. */
2356DEFUN (config_end,
2357 config_end_cmd,
2358 "end",
2359 "End current mode and change to enable mode.")
2360{
2361 switch (vty->node)
2362 {
2363 case VIEW_NODE:
2364 case ENABLE_NODE:
2365 /* Nothing to do. */
2366 break;
2367 case CONFIG_NODE:
2368 case INTERFACE_NODE:
2369 case ZEBRA_NODE:
2370 case RIP_NODE:
2371 case RIPNG_NODE:
2372 case BGP_NODE:
2373 case BGP_VPNV4_NODE:
2374 case BGP_IPV4_NODE:
2375 case BGP_IPV4M_NODE:
2376 case BGP_IPV6_NODE:
2377 case RMAP_NODE:
2378 case OSPF_NODE:
2379 case OSPF6_NODE:
2380 case KEYCHAIN_NODE:
2381 case KEYCHAIN_KEY_NODE:
2382 case MASC_NODE:
2383 case VTY_NODE:
2384 vty_config_unlock (vty);
2385 vty->node = ENABLE_NODE;
2386 break;
2387 default:
2388 break;
2389 }
2390 return CMD_SUCCESS;
2391}
2392
2393/* Show version. */
2394DEFUN (show_version,
2395 show_version_cmd,
2396 "show version",
2397 SHOW_STR
2398 "Displays zebra version\n")
2399{
paule8f29842003-08-12 13:08:31 +00002400 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION,
paul718e3742002-12-13 20:15:29 +00002401 host_name,
2402 VTY_NEWLINE);
2403 vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
2404
2405 return CMD_SUCCESS;
2406}
2407
2408/* Help display function for all node. */
2409DEFUN (config_help,
2410 config_help_cmd,
2411 "help",
2412 "Description of the interactive help system\n")
2413{
2414 vty_out (vty,
2415 "Zebra VTY provides advanced help feature. When you need help,%s\
2416anytime at the command line please press '?'.%s\
2417%s\
2418If nothing matches, the help list will be empty and you must backup%s\
2419 until entering a '?' shows the available options.%s\
2420Two styles of help are provided:%s\
24211. Full help is available when you are ready to enter a%s\
2422command argument (e.g. 'show ?') and describes each possible%s\
2423argument.%s\
24242. Partial help is provided when an abbreviated argument is entered%s\
2425 and you want to know what arguments match the input%s\
2426 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2427 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2428 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2429 return CMD_SUCCESS;
2430}
2431
2432/* Help display function for all node. */
2433DEFUN (config_list,
2434 config_list_cmd,
2435 "list",
2436 "Print command list\n")
2437{
2438 int i;
2439 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2440 struct cmd_element *cmd;
2441
2442 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2443 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2444 vty_out (vty, " %s%s", cmd->string,
2445 VTY_NEWLINE);
2446 return CMD_SUCCESS;
2447}
2448
2449/* Write current configuration into file. */
2450DEFUN (config_write_file,
2451 config_write_file_cmd,
2452 "write file",
2453 "Write running configuration to memory, network, or terminal\n"
2454 "Write to configuration file\n")
2455{
2456 int i;
2457 int fd;
2458 struct cmd_node *node;
2459 char *config_file;
2460 char *config_file_tmp = NULL;
2461 char *config_file_sav = NULL;
2462 struct vty *file_vty;
2463
2464 /* Check and see if we are operating under vtysh configuration */
2465 if (host.config == NULL)
2466 {
2467 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2468 VTY_NEWLINE);
2469 return CMD_WARNING;
2470 }
2471
2472 /* Get filename. */
2473 config_file = host.config;
2474
2475 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2476 strcpy (config_file_sav, config_file);
2477 strcat (config_file_sav, CONF_BACKUP_EXT);
2478
2479
2480 config_file_tmp = malloc (strlen (config_file) + 8);
2481 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2482
2483 /* Open file to configuration write. */
2484 fd = mkstemp (config_file_tmp);
2485 if (fd < 0)
2486 {
2487 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2488 VTY_NEWLINE);
2489 free (config_file_tmp);
2490 free (config_file_sav);
2491 return CMD_WARNING;
2492 }
2493
2494 /* Make vty for configuration file. */
2495 file_vty = vty_new ();
2496 file_vty->fd = fd;
2497 file_vty->type = VTY_FILE;
2498
2499 /* Config file header print. */
2500 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2501 vty_time_print (file_vty, 1);
2502 vty_out (file_vty, "!\n");
2503
2504 for (i = 0; i < vector_max (cmdvec); i++)
2505 if ((node = vector_slot (cmdvec, i)) && node->func)
2506 {
2507 if ((*node->func) (file_vty))
2508 vty_out (file_vty, "!\n");
2509 }
2510 vty_close (file_vty);
2511
2512 if (unlink (config_file_sav) != 0)
2513 if (errno != ENOENT)
2514 {
2515 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2516 VTY_NEWLINE);
2517 free (config_file_sav);
2518 free (config_file_tmp);
2519 unlink (config_file_tmp);
2520 return CMD_WARNING;
2521 }
2522 if (link (config_file, config_file_sav) != 0)
2523 {
2524 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2525 VTY_NEWLINE);
2526 free (config_file_sav);
2527 free (config_file_tmp);
2528 unlink (config_file_tmp);
2529 return CMD_WARNING;
2530 }
2531 sync ();
2532 if (unlink (config_file) != 0)
2533 {
2534 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2535 VTY_NEWLINE);
2536 free (config_file_sav);
2537 free (config_file_tmp);
2538 unlink (config_file_tmp);
2539 return CMD_WARNING;
2540 }
2541 if (link (config_file_tmp, config_file) != 0)
2542 {
2543 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2544 VTY_NEWLINE);
2545 free (config_file_sav);
2546 free (config_file_tmp);
2547 unlink (config_file_tmp);
2548 return CMD_WARNING;
2549 }
2550 unlink (config_file_tmp);
2551 sync ();
2552
2553 free (config_file_sav);
2554 free (config_file_tmp);
2555 vty_out (vty, "Configuration saved to %s%s", config_file,
2556 VTY_NEWLINE);
2557 return CMD_SUCCESS;
2558}
2559
2560ALIAS (config_write_file,
2561 config_write_cmd,
2562 "write",
2563 "Write running configuration to memory, network, or terminal\n")
2564
2565ALIAS (config_write_file,
2566 config_write_memory_cmd,
2567 "write memory",
2568 "Write running configuration to memory, network, or terminal\n"
2569 "Write configuration to the file (same as write file)\n")
2570
2571ALIAS (config_write_file,
2572 copy_runningconfig_startupconfig_cmd,
2573 "copy running-config startup-config",
2574 "Copy configuration\n"
2575 "Copy running config to... \n"
2576 "Copy running config to startup config (same as write file)\n")
2577
2578/* Write current configuration into the terminal. */
2579DEFUN (config_write_terminal,
2580 config_write_terminal_cmd,
2581 "write terminal",
2582 "Write running configuration to memory, network, or terminal\n"
2583 "Write to terminal\n")
2584{
2585 int i;
2586 struct cmd_node *node;
2587
2588 if (vty->type == VTY_SHELL_SERV)
2589 {
2590 for (i = 0; i < vector_max (cmdvec); i++)
2591 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2592 {
2593 if ((*node->func) (vty))
2594 vty_out (vty, "!%s", VTY_NEWLINE);
2595 }
2596 }
2597 else
2598 {
2599 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2600 VTY_NEWLINE);
2601 vty_out (vty, "!%s", VTY_NEWLINE);
2602
2603 for (i = 0; i < vector_max (cmdvec); i++)
2604 if ((node = vector_slot (cmdvec, i)) && node->func)
2605 {
2606 if ((*node->func) (vty))
2607 vty_out (vty, "!%s", VTY_NEWLINE);
2608 }
2609 vty_out (vty, "end%s",VTY_NEWLINE);
2610 }
2611 return CMD_SUCCESS;
2612}
2613
2614/* Write current configuration into the terminal. */
2615ALIAS (config_write_terminal,
2616 show_running_config_cmd,
2617 "show running-config",
2618 SHOW_STR
2619 "running configuration\n")
2620
2621/* Write startup configuration into the terminal. */
2622DEFUN (show_startup_config,
2623 show_startup_config_cmd,
2624 "show startup-config",
2625 SHOW_STR
2626 "Contentes of startup configuration\n")
2627{
2628 char buf[BUFSIZ];
2629 FILE *confp;
2630
2631 confp = fopen (host.config, "r");
2632 if (confp == NULL)
2633 {
2634 vty_out (vty, "Can't open configuration file [%s]%s",
2635 host.config, VTY_NEWLINE);
2636 return CMD_WARNING;
2637 }
2638
2639 while (fgets (buf, BUFSIZ, confp))
2640 {
2641 char *cp = buf;
2642
2643 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2644 cp++;
2645 *cp = '\0';
2646
2647 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2648 }
2649
2650 fclose (confp);
2651
2652 return CMD_SUCCESS;
2653}
2654
2655/* Hostname configuration */
2656DEFUN (config_hostname,
2657 hostname_cmd,
2658 "hostname WORD",
2659 "Set system's network name\n"
2660 "This system's network name\n")
2661{
2662 if (!isalpha((int) *argv[0]))
2663 {
2664 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2665 return CMD_WARNING;
2666 }
2667
2668 if (host.name)
2669 XFREE (0, host.name);
2670
2671 host.name = strdup (argv[0]);
2672 return CMD_SUCCESS;
2673}
2674
2675DEFUN (config_no_hostname,
2676 no_hostname_cmd,
2677 "no hostname [HOSTNAME]",
2678 NO_STR
2679 "Reset system's network name\n"
2680 "Host name of this router\n")
2681{
2682 if (host.name)
2683 XFREE (0, host.name);
2684 host.name = NULL;
2685 return CMD_SUCCESS;
2686}
2687
2688/* VTY interface password set. */
2689DEFUN (config_password, password_cmd,
2690 "password (8|) WORD",
2691 "Assign the terminal connection password\n"
2692 "Specifies a HIDDEN password will follow\n"
2693 "dummy string \n"
2694 "The HIDDEN line password string\n")
2695{
2696 /* Argument check. */
2697 if (argc == 0)
2698 {
2699 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2700 return CMD_WARNING;
2701 }
2702
2703 if (argc == 2)
2704 {
2705 if (*argv[0] == '8')
2706 {
2707 if (host.password)
2708 XFREE (0, host.password);
2709 host.password = NULL;
2710 if (host.password_encrypt)
2711 XFREE (0, host.password_encrypt);
2712 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2713 return CMD_SUCCESS;
2714 }
2715 else
2716 {
2717 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2718 return CMD_WARNING;
2719 }
2720 }
2721
2722 if (!isalnum ((int) *argv[0]))
2723 {
2724 vty_out (vty,
2725 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2726 return CMD_WARNING;
2727 }
2728
2729 if (host.password)
2730 XFREE (0, host.password);
2731 host.password = NULL;
2732
2733 if (host.encrypt)
2734 {
2735 if (host.password_encrypt)
2736 XFREE (0, host.password_encrypt);
2737 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2738 }
2739 else
2740 host.password = XSTRDUP (0, argv[0]);
2741
2742 return CMD_SUCCESS;
2743}
2744
2745ALIAS (config_password, password_text_cmd,
2746 "password LINE",
2747 "Assign the terminal connection password\n"
2748 "The UNENCRYPTED (cleartext) line password\n")
2749
2750/* VTY enable password set. */
2751DEFUN (config_enable_password, enable_password_cmd,
2752 "enable password (8|) WORD",
2753 "Modify enable password parameters\n"
2754 "Assign the privileged level password\n"
2755 "Specifies a HIDDEN password will follow\n"
2756 "dummy string \n"
2757 "The HIDDEN 'enable' password string\n")
2758{
2759 /* Argument check. */
2760 if (argc == 0)
2761 {
2762 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2763 return CMD_WARNING;
2764 }
2765
2766 /* Crypt type is specified. */
2767 if (argc == 2)
2768 {
2769 if (*argv[0] == '8')
2770 {
2771 if (host.enable)
2772 XFREE (0, host.enable);
2773 host.enable = NULL;
2774
2775 if (host.enable_encrypt)
2776 XFREE (0, host.enable_encrypt);
2777 host.enable_encrypt = XSTRDUP (0, argv[1]);
2778
2779 return CMD_SUCCESS;
2780 }
2781 else
2782 {
2783 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2784 return CMD_WARNING;
2785 }
2786 }
2787
2788 if (!isalnum ((int) *argv[0]))
2789 {
2790 vty_out (vty,
2791 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2792 return CMD_WARNING;
2793 }
2794
2795 if (host.enable)
2796 XFREE (0, host.enable);
2797 host.enable = NULL;
2798
2799 /* Plain password input. */
2800 if (host.encrypt)
2801 {
2802 if (host.enable_encrypt)
2803 XFREE (0, host.enable_encrypt);
2804 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2805 }
2806 else
2807 host.enable = XSTRDUP (0, argv[0]);
2808
2809 return CMD_SUCCESS;
2810}
2811
2812ALIAS (config_enable_password,
2813 enable_password_text_cmd,
2814 "enable password LINE",
2815 "Modify enable password parameters\n"
2816 "Assign the privileged level password\n"
2817 "The UNENCRYPTED (cleartext) 'enable' password\n")
2818
2819/* VTY enable password delete. */
2820DEFUN (no_config_enable_password, no_enable_password_cmd,
2821 "no enable password",
2822 NO_STR
2823 "Modify enable password parameters\n"
2824 "Assign the privileged level password\n")
2825{
2826 if (host.enable)
2827 XFREE (0, host.enable);
2828 host.enable = NULL;
2829
2830 if (host.enable_encrypt)
2831 XFREE (0, host.enable_encrypt);
2832 host.enable_encrypt = NULL;
2833
2834 return CMD_SUCCESS;
2835}
2836
2837DEFUN (service_password_encrypt,
2838 service_password_encrypt_cmd,
2839 "service password-encryption",
2840 "Set up miscellaneous service\n"
2841 "Enable encrypted passwords\n")
2842{
2843 if (host.encrypt)
2844 return CMD_SUCCESS;
2845
2846 host.encrypt = 1;
2847
2848 if (host.password)
2849 {
2850 if (host.password_encrypt)
2851 XFREE (0, host.password_encrypt);
2852 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2853 }
2854 if (host.enable)
2855 {
2856 if (host.enable_encrypt)
2857 XFREE (0, host.enable_encrypt);
2858 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2859 }
2860
2861 return CMD_SUCCESS;
2862}
2863
2864DEFUN (no_service_password_encrypt,
2865 no_service_password_encrypt_cmd,
2866 "no service password-encryption",
2867 NO_STR
2868 "Set up miscellaneous service\n"
2869 "Enable encrypted passwords\n")
2870{
2871 if (! host.encrypt)
2872 return CMD_SUCCESS;
2873
2874 host.encrypt = 0;
2875
2876 if (host.password_encrypt)
2877 XFREE (0, host.password_encrypt);
2878 host.password_encrypt = NULL;
2879
2880 if (host.enable_encrypt)
2881 XFREE (0, host.enable_encrypt);
2882 host.enable_encrypt = NULL;
2883
2884 return CMD_SUCCESS;
2885}
2886
2887DEFUN (config_terminal_length, config_terminal_length_cmd,
2888 "terminal length <0-512>",
2889 "Set terminal line parameters\n"
2890 "Set number of lines on a screen\n"
2891 "Number of lines on screen (0 for no pausing)\n")
2892{
2893 int lines;
2894 char *endptr = NULL;
2895
2896 lines = strtol (argv[0], &endptr, 10);
2897 if (lines < 0 || lines > 512 || *endptr != '\0')
2898 {
2899 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2900 return CMD_WARNING;
2901 }
2902 vty->lines = lines;
2903
2904 return CMD_SUCCESS;
2905}
2906
2907DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2908 "terminal no length",
2909 "Set terminal line parameters\n"
2910 NO_STR
2911 "Set number of lines on a screen\n")
2912{
2913 vty->lines = -1;
2914 return CMD_SUCCESS;
2915}
2916
2917DEFUN (service_terminal_length, service_terminal_length_cmd,
2918 "service terminal-length <0-512>",
2919 "Set up miscellaneous service\n"
2920 "System wide terminal length configuration\n"
2921 "Number of lines of VTY (0 means no line control)\n")
2922{
2923 int lines;
2924 char *endptr = NULL;
2925
2926 lines = strtol (argv[0], &endptr, 10);
2927 if (lines < 0 || lines > 512 || *endptr != '\0')
2928 {
2929 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2930 return CMD_WARNING;
2931 }
2932 host.lines = lines;
2933
2934 return CMD_SUCCESS;
2935}
2936
2937DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2938 "no service terminal-length [<0-512>]",
2939 NO_STR
2940 "Set up miscellaneous service\n"
2941 "System wide terminal length configuration\n"
2942 "Number of lines of VTY (0 means no line control)\n")
2943{
2944 host.lines = -1;
2945 return CMD_SUCCESS;
2946}
2947
2948DEFUN (config_log_stdout,
2949 config_log_stdout_cmd,
2950 "log stdout",
2951 "Logging control\n"
2952 "Logging goes to stdout\n")
2953{
2954 zlog_set_flag (NULL, ZLOG_STDOUT);
2955 host.log_stdout = 1;
2956 return CMD_SUCCESS;
2957}
2958
2959DEFUN (no_config_log_stdout,
2960 no_config_log_stdout_cmd,
2961 "no log stdout",
2962 NO_STR
2963 "Logging control\n"
2964 "Cancel logging to stdout\n")
2965{
2966 zlog_reset_flag (NULL, ZLOG_STDOUT);
2967 host.log_stdout = 0;
2968 return CMD_SUCCESS;
2969}
2970
2971DEFUN (config_log_file,
2972 config_log_file_cmd,
2973 "log file FILENAME",
2974 "Logging control\n"
2975 "Logging to file\n"
2976 "Logging filename\n")
2977{
2978 int ret;
2979 char *cwd;
2980 char *fullpath;
2981
2982 /* Path detection. */
2983 if (! IS_DIRECTORY_SEP (*argv[0]))
2984 {
2985 cwd = getcwd (NULL, MAXPATHLEN);
2986 fullpath = XMALLOC (MTYPE_TMP,
2987 strlen (cwd) + strlen (argv[0]) + 2);
2988 sprintf (fullpath, "%s/%s", cwd, argv[0]);
2989 }
2990 else
2991 fullpath = argv[0];
2992
2993 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
2994
2995 if (!ret)
2996 {
2997 vty_out (vty, "can't open logfile %s\n", argv[0]);
2998 return CMD_WARNING;
2999 }
3000
3001 if (host.logfile)
3002 XFREE (MTYPE_TMP, host.logfile);
3003
3004 host.logfile = strdup (argv[0]);
3005
3006 return CMD_SUCCESS;
3007}
3008
3009DEFUN (no_config_log_file,
3010 no_config_log_file_cmd,
3011 "no log file [FILENAME]",
3012 NO_STR
3013 "Logging control\n"
3014 "Cancel logging to file\n"
3015 "Logging file name\n")
3016{
3017 zlog_reset_file (NULL);
3018
3019 if (host.logfile)
3020 XFREE (MTYPE_TMP, host.logfile);
3021
3022 host.logfile = NULL;
3023
3024 return CMD_SUCCESS;
3025}
3026
3027DEFUN (config_log_syslog,
3028 config_log_syslog_cmd,
3029 "log syslog",
3030 "Logging control\n"
3031 "Logging goes to syslog\n")
3032{
3033 zlog_set_flag (NULL, ZLOG_SYSLOG);
3034 host.log_syslog = 1;
paul12ab19f2003-07-26 06:14:55 +00003035 zlog_default->facility = LOG_DAEMON;
3036 return CMD_SUCCESS;
3037}
3038
3039DEFUN (config_log_syslog_facility,
3040 config_log_syslog_facility_cmd,
3041 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3042 "Logging control\n"
3043 "Logging goes to syslog\n"
3044 "Facility parameter for syslog messages\n"
3045 "Kernel\n"
3046 "User process\n"
3047 "Mail system\n"
3048 "System daemons\n"
3049 "Authorization system\n"
3050 "Syslog itself\n"
3051 "Line printer system\n"
3052 "USENET news\n"
3053 "Unix-to-Unix copy system\n"
3054 "Cron/at facility\n"
3055 "Local use\n"
3056 "Local use\n"
3057 "Local use\n"
3058 "Local use\n"
3059 "Local use\n"
3060 "Local use\n"
3061 "Local use\n"
3062 "Local use\n")
3063{
3064 int facility = LOG_DAEMON;
3065
3066 zlog_set_flag (NULL, ZLOG_SYSLOG);
3067 host.log_syslog = 1;
3068
3069 if (strncmp (argv[0], "kern", 1) == 0)
3070 facility = LOG_KERN;
3071 else if (strncmp (argv[0], "user", 2) == 0)
3072 facility = LOG_USER;
3073 else if (strncmp (argv[0], "mail", 1) == 0)
3074 facility = LOG_MAIL;
3075 else if (strncmp (argv[0], "daemon", 1) == 0)
3076 facility = LOG_DAEMON;
3077 else if (strncmp (argv[0], "auth", 1) == 0)
3078 facility = LOG_AUTH;
3079 else if (strncmp (argv[0], "syslog", 1) == 0)
3080 facility = LOG_SYSLOG;
3081 else if (strncmp (argv[0], "lpr", 2) == 0)
3082 facility = LOG_LPR;
3083 else if (strncmp (argv[0], "news", 1) == 0)
3084 facility = LOG_NEWS;
3085 else if (strncmp (argv[0], "uucp", 2) == 0)
3086 facility = LOG_UUCP;
3087 else if (strncmp (argv[0], "cron", 1) == 0)
3088 facility = LOG_CRON;
3089 else if (strncmp (argv[0], "local0", 6) == 0)
3090 facility = LOG_LOCAL0;
3091 else if (strncmp (argv[0], "local1", 6) == 0)
3092 facility = LOG_LOCAL1;
3093 else if (strncmp (argv[0], "local2", 6) == 0)
3094 facility = LOG_LOCAL2;
3095 else if (strncmp (argv[0], "local3", 6) == 0)
3096 facility = LOG_LOCAL3;
3097 else if (strncmp (argv[0], "local4", 6) == 0)
3098 facility = LOG_LOCAL4;
3099 else if (strncmp (argv[0], "local5", 6) == 0)
3100 facility = LOG_LOCAL5;
3101 else if (strncmp (argv[0], "local6", 6) == 0)
3102 facility = LOG_LOCAL6;
3103 else if (strncmp (argv[0], "local7", 6) == 0)
3104 facility = LOG_LOCAL7;
3105
3106 zlog_default->facility = facility;
3107
paul718e3742002-12-13 20:15:29 +00003108 return CMD_SUCCESS;
3109}
3110
3111DEFUN (no_config_log_syslog,
3112 no_config_log_syslog_cmd,
3113 "no log syslog",
3114 NO_STR
3115 "Logging control\n"
3116 "Cancel logging to syslog\n")
3117{
3118 zlog_reset_flag (NULL, ZLOG_SYSLOG);
3119 host.log_syslog = 0;
paul12ab19f2003-07-26 06:14:55 +00003120 zlog_default->facility = LOG_DAEMON;
paul718e3742002-12-13 20:15:29 +00003121 return CMD_SUCCESS;
3122}
3123
paul12ab19f2003-07-26 06:14:55 +00003124ALIAS (no_config_log_syslog,
3125 no_config_log_syslog_facility_cmd,
3126 "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3127 NO_STR
3128 "Logging control\n"
3129 "Logging goes to syslog\n"
3130 "Facility parameter for syslog messages\n"
3131 "Kernel\n"
3132 "User process\n"
3133 "Mail system\n"
3134 "System daemons\n"
3135 "Authorization system\n"
3136 "Syslog itself\n"
3137 "Line printer system\n"
3138 "USENET news\n"
3139 "Unix-to-Unix copy system\n"
3140 "Cron/at facility\n"
3141 "Local use\n"
3142 "Local use\n"
3143 "Local use\n"
3144 "Local use\n"
3145 "Local use\n"
3146 "Local use\n"
3147 "Local use\n"
3148 "Local use\n")
3149
paul718e3742002-12-13 20:15:29 +00003150DEFUN (config_log_trap,
3151 config_log_trap_cmd,
3152 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3153 "Logging control\n"
3154 "Limit logging to specifed level\n")
3155{
3156 int new_level ;
3157
3158 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
3159 {
3160 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
3161 /* found new logging level */
3162 {
3163 zlog_default->maskpri = new_level;
3164 return CMD_SUCCESS;
3165 }
3166 }
3167 return CMD_ERR_NO_MATCH;
3168}
3169
3170DEFUN (no_config_log_trap,
3171 no_config_log_trap_cmd,
3172 "no log trap",
3173 NO_STR
3174 "Logging control\n"
3175 "Permit all logging information\n")
3176{
3177 zlog_default->maskpri = LOG_DEBUG;
3178 return CMD_SUCCESS;
3179}
3180
3181DEFUN (config_log_record_priority,
3182 config_log_record_priority_cmd,
3183 "log record-priority",
3184 "Logging control\n"
3185 "Log the priority of the message within the message\n")
3186{
3187 zlog_default->record_priority = 1 ;
3188 return CMD_SUCCESS;
3189}
3190
3191DEFUN (no_config_log_record_priority,
3192 no_config_log_record_priority_cmd,
3193 "no log record-priority",
3194 NO_STR
3195 "Logging control\n"
3196 "Do not log the priority of the message within the message\n")
3197{
3198 zlog_default->record_priority = 0 ;
3199 return CMD_SUCCESS;
3200}
3201
3202
3203DEFUN (banner_motd_default,
3204 banner_motd_default_cmd,
3205 "banner motd default",
3206 "Set banner string\n"
3207 "Strings for motd\n"
3208 "Default string\n")
3209{
3210 host.motd = default_motd;
3211 return CMD_SUCCESS;
3212}
3213
3214DEFUN (no_banner_motd,
3215 no_banner_motd_cmd,
3216 "no banner motd",
3217 NO_STR
3218 "Set banner string\n"
3219 "Strings for motd\n")
3220{
3221 host.motd = NULL;
3222 return CMD_SUCCESS;
3223}
3224
3225/* Set config filename. Called from vty.c */
3226void
3227host_config_set (char *filename)
3228{
3229 host.config = strdup (filename);
3230}
3231
3232void
3233install_default (enum node_type node)
3234{
3235 install_element (node, &config_exit_cmd);
3236 install_element (node, &config_quit_cmd);
3237 install_element (node, &config_end_cmd);
3238 install_element (node, &config_help_cmd);
3239 install_element (node, &config_list_cmd);
3240
3241 install_element (node, &config_write_terminal_cmd);
3242 install_element (node, &config_write_file_cmd);
3243 install_element (node, &config_write_memory_cmd);
3244 install_element (node, &config_write_cmd);
3245 install_element (node, &show_running_config_cmd);
3246}
3247
3248/* Initialize command interface. Install basic nodes and commands. */
3249void
3250cmd_init (int terminal)
3251{
3252 /* Allocate initial top vector of commands. */
3253 cmdvec = vector_init (VECTOR_MIN_SIZE);
3254
3255 /* Default host value settings. */
3256 host.name = NULL;
3257 host.password = NULL;
3258 host.enable = NULL;
3259 host.logfile = NULL;
3260 host.config = NULL;
3261 host.lines = -1;
3262 host.motd = default_motd;
3263
3264 /* Install top nodes. */
3265 install_node (&view_node, NULL);
3266 install_node (&enable_node, NULL);
3267 install_node (&auth_node, NULL);
3268 install_node (&auth_enable_node, NULL);
3269 install_node (&config_node, config_write_host);
3270
3271 /* Each node's basic commands. */
3272 install_element (VIEW_NODE, &show_version_cmd);
3273 if (terminal)
3274 {
3275 install_element (VIEW_NODE, &config_list_cmd);
3276 install_element (VIEW_NODE, &config_exit_cmd);
3277 install_element (VIEW_NODE, &config_quit_cmd);
3278 install_element (VIEW_NODE, &config_help_cmd);
3279 install_element (VIEW_NODE, &config_enable_cmd);
3280 install_element (VIEW_NODE, &config_terminal_length_cmd);
3281 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3282 }
3283
3284 if (terminal)
3285 {
3286 install_default (ENABLE_NODE);
3287 install_element (ENABLE_NODE, &config_disable_cmd);
3288 install_element (ENABLE_NODE, &config_terminal_cmd);
3289 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3290 }
3291 install_element (ENABLE_NODE, &show_startup_config_cmd);
3292 install_element (ENABLE_NODE, &show_version_cmd);
3293 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3294 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3295
3296 if (terminal)
3297 install_default (CONFIG_NODE);
3298 install_element (CONFIG_NODE, &hostname_cmd);
3299 install_element (CONFIG_NODE, &no_hostname_cmd);
3300 install_element (CONFIG_NODE, &password_cmd);
3301 install_element (CONFIG_NODE, &password_text_cmd);
3302 install_element (CONFIG_NODE, &enable_password_cmd);
3303 install_element (CONFIG_NODE, &enable_password_text_cmd);
3304 install_element (CONFIG_NODE, &no_enable_password_cmd);
3305 if (terminal)
3306 {
3307 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3308 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3309 install_element (CONFIG_NODE, &config_log_file_cmd);
3310 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3311 install_element (CONFIG_NODE, &config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003312 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003313 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003314 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003315 install_element (CONFIG_NODE, &config_log_trap_cmd);
3316 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3317 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3318 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3319 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3320 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3321 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3322 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3323 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3324 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3325 }
3326
paul9ab68122003-01-18 01:16:20 +00003327 if (terminal)
3328 {
3329 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3330 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3331 }
paul718e3742002-12-13 20:15:29 +00003332 srand(time(NULL));
3333}