Bug #362 is fixed now.
[jleu-quagga.git] / lib / command.c
blobf3d96ede0134f26cd3a53cb356eb9ac02cf82408
1 /*
2 $Id$
4 Command interpreter routine for virtual terminal [aka TeletYpe]
5 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
7 This file is part of GNU Zebra.
9 GNU Zebra is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published
11 by the Free Software Foundation; either version 2, or (at your
12 option) any later version.
14 GNU Zebra is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GNU Zebra; see the file COPYING. If not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 #include <zebra.h>
27 #include "memory.h"
28 #include "log.h"
29 #include <lib/version.h>
30 #include "thread.h"
31 #include "vector.h"
32 #include "vty.h"
33 #include "command.h"
34 #include "workqueue.h"
36 /* Command vector which includes some level of command lists. Normally
37 each daemon maintains each own cmdvec. */
38 vector cmdvec = NULL;
40 /* Host information structure. */
41 struct host host;
43 /* Standard command node structures. */
44 struct cmd_node auth_node =
46 AUTH_NODE,
47 "Password: ",
50 struct cmd_node view_node =
52 VIEW_NODE,
53 "%s> ",
56 struct cmd_node auth_enable_node =
58 AUTH_ENABLE_NODE,
59 "Password: ",
62 struct cmd_node enable_node =
64 ENABLE_NODE,
65 "%s# ",
68 struct cmd_node config_node =
70 CONFIG_NODE,
71 "%s(config)# ",
75 /* Default motd string. */
76 const char *default_motd =
77 "\r\n\
78 Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
79 " QUAGGA_COPYRIGHT "\r\n\
80 \r\n";
83 static struct facility_map {
84 int facility;
85 const char *name;
86 size_t match;
87 } syslog_facilities[] =
89 { LOG_KERN, "kern", 1 },
90 { LOG_USER, "user", 2 },
91 { LOG_MAIL, "mail", 1 },
92 { LOG_DAEMON, "daemon", 1 },
93 { LOG_AUTH, "auth", 1 },
94 { LOG_SYSLOG, "syslog", 1 },
95 { LOG_LPR, "lpr", 2 },
96 { LOG_NEWS, "news", 1 },
97 { LOG_UUCP, "uucp", 2 },
98 { LOG_CRON, "cron", 1 },
99 #ifdef LOG_FTP
100 { LOG_FTP, "ftp", 1 },
101 #endif
102 { LOG_LOCAL0, "local0", 6 },
103 { LOG_LOCAL1, "local1", 6 },
104 { LOG_LOCAL2, "local2", 6 },
105 { LOG_LOCAL3, "local3", 6 },
106 { LOG_LOCAL4, "local4", 6 },
107 { LOG_LOCAL5, "local5", 6 },
108 { LOG_LOCAL6, "local6", 6 },
109 { LOG_LOCAL7, "local7", 6 },
110 { 0, NULL, 0 },
113 static const char *
114 facility_name(int facility)
116 struct facility_map *fm;
118 for (fm = syslog_facilities; fm->name; fm++)
119 if (fm->facility == facility)
120 return fm->name;
121 return "";
124 static int
125 facility_match(const char *str)
127 struct facility_map *fm;
129 for (fm = syslog_facilities; fm->name; fm++)
130 if (!strncmp(str,fm->name,fm->match))
131 return fm->facility;
132 return -1;
135 static int
136 level_match(const char *s)
138 int level ;
140 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
141 if (!strncmp (s, zlog_priority[level], 2))
142 return level;
143 return ZLOG_DISABLED;
146 /* This is called from main when a daemon is invoked with -v or --version. */
147 void
148 print_version (const char *progname)
150 printf ("%s version %s\n", progname, QUAGGA_VERSION);
151 printf ("%s\n", QUAGGA_COPYRIGHT);
155 /* Utility function to concatenate argv argument into a single string
156 with inserting ' ' character between each argument. */
157 char *
158 argv_concat (const char **argv, int argc, int shift)
160 int i;
161 size_t len;
162 char *str;
163 char *p;
165 len = 0;
166 for (i = shift; i < argc; i++)
167 len += strlen(argv[i])+1;
168 if (!len)
169 return NULL;
170 p = str = XMALLOC(MTYPE_TMP, len);
171 for (i = shift; i < argc; i++)
173 size_t arglen;
174 memcpy(p, argv[i], (arglen = strlen(argv[i])));
175 p += arglen;
176 *p++ = ' ';
178 *(p-1) = '\0';
179 return str;
182 /* Install top node of command vector. */
183 void
184 install_node (struct cmd_node *node,
185 int (*func) (struct vty *))
187 vector_set_index (cmdvec, node->node, node);
188 node->func = func;
189 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
192 /* Compare two command's string. Used in sort_node (). */
193 static int
194 cmp_node (const void *p, const void *q)
196 const struct cmd_element *a = *(struct cmd_element **)p;
197 const struct cmd_element *b = *(struct cmd_element **)q;
199 return strcmp (a->string, b->string);
202 static int
203 cmp_desc (const void *p, const void *q)
205 const struct desc *a = *(struct desc **)p;
206 const struct desc *b = *(struct desc **)q;
208 return strcmp (a->cmd, b->cmd);
211 /* Sort each node's command element according to command string. */
212 void
213 sort_node ()
215 unsigned int i, j;
216 struct cmd_node *cnode;
217 vector descvec;
218 struct cmd_element *cmd_element;
220 for (i = 0; i < vector_active (cmdvec); i++)
221 if ((cnode = vector_slot (cmdvec, i)) != NULL)
223 vector cmd_vector = cnode->cmd_vector;
224 qsort (cmd_vector->index, vector_active (cmd_vector),
225 sizeof (void *), cmp_node);
227 for (j = 0; j < vector_active (cmd_vector); j++)
228 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
229 && vector_active (cmd_element->strvec))
231 descvec = vector_slot (cmd_element->strvec,
232 vector_active (cmd_element->strvec) - 1);
233 qsort (descvec->index, vector_active (descvec),
234 sizeof (void *), cmp_desc);
239 /* Breaking up string into each command piece. I assume given
240 character is separated by a space character. Return value is a
241 vector which includes char ** data element. */
242 vector
243 cmd_make_strvec (const char *string)
245 const char *cp, *start;
246 char *token;
247 int strlen;
248 vector strvec;
250 if (string == NULL)
251 return NULL;
253 cp = string;
255 /* Skip white spaces. */
256 while (isspace ((int) *cp) && *cp != '\0')
257 cp++;
259 /* Return if there is only white spaces */
260 if (*cp == '\0')
261 return NULL;
263 if (*cp == '!' || *cp == '#')
264 return NULL;
266 /* Prepare return vector. */
267 strvec = vector_init (VECTOR_MIN_SIZE);
269 /* Copy each command piece and set into vector. */
270 while (1)
272 start = cp;
273 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
274 *cp != '\0')
275 cp++;
276 strlen = cp - start;
277 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
278 memcpy (token, start, strlen);
279 *(token + strlen) = '\0';
280 vector_set (strvec, token);
282 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
283 *cp != '\0')
284 cp++;
286 if (*cp == '\0')
287 return strvec;
291 /* Free allocated string vector. */
292 void
293 cmd_free_strvec (vector v)
295 unsigned int i;
296 char *cp;
298 if (!v)
299 return;
301 for (i = 0; i < vector_active (v); i++)
302 if ((cp = vector_slot (v, i)) != NULL)
303 XFREE (MTYPE_STRVEC, cp);
305 vector_free (v);
308 /* Fetch next description. Used in cmd_make_descvec(). */
309 static char *
310 cmd_desc_str (const char **string)
312 const char *cp, *start;
313 char *token;
314 int strlen;
316 cp = *string;
318 if (cp == NULL)
319 return NULL;
321 /* Skip white spaces. */
322 while (isspace ((int) *cp) && *cp != '\0')
323 cp++;
325 /* Return if there is only white spaces */
326 if (*cp == '\0')
327 return NULL;
329 start = cp;
331 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
332 cp++;
334 strlen = cp - start;
335 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
336 memcpy (token, start, strlen);
337 *(token + strlen) = '\0';
339 *string = cp;
341 return token;
344 /* New string vector. */
345 static vector
346 cmd_make_descvec (const char *string, const char *descstr)
348 int multiple = 0;
349 const char *sp;
350 char *token;
351 int len;
352 const char *cp;
353 const char *dp;
354 vector allvec;
355 vector strvec = NULL;
356 struct desc *desc;
358 cp = string;
359 dp = descstr;
361 if (cp == NULL)
362 return NULL;
364 allvec = vector_init (VECTOR_MIN_SIZE);
366 while (1)
368 while (isspace ((int) *cp) && *cp != '\0')
369 cp++;
371 if (*cp == '(')
373 multiple = 1;
374 cp++;
376 if (*cp == ')')
378 multiple = 0;
379 cp++;
381 if (*cp == '|')
383 if (! multiple)
385 fprintf (stderr, "Command parse error!: %s\n", string);
386 exit (1);
388 cp++;
391 while (isspace ((int) *cp) && *cp != '\0')
392 cp++;
394 if (*cp == '(')
396 multiple = 1;
397 cp++;
400 if (*cp == '\0')
401 return allvec;
403 sp = cp;
405 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
406 cp++;
408 len = cp - sp;
410 token = XMALLOC (MTYPE_STRVEC, len + 1);
411 memcpy (token, sp, len);
412 *(token + len) = '\0';
414 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
415 desc->cmd = token;
416 desc->str = cmd_desc_str (&dp);
418 if (multiple)
420 if (multiple == 1)
422 strvec = vector_init (VECTOR_MIN_SIZE);
423 vector_set (allvec, strvec);
425 multiple++;
427 else
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
432 vector_set (strvec, desc);
436 /* Count mandantory string vector size. This is to determine inputed
437 command has enough command length. */
438 static int
439 cmd_cmdsize (vector strvec)
441 unsigned int i;
442 int size = 0;
443 vector descvec;
444 struct desc *desc;
446 for (i = 0; i < vector_active (strvec); i++)
447 if ((descvec = vector_slot (strvec, i)) != NULL)
449 if ((vector_active (descvec)) == 1
450 && (desc = vector_slot (descvec, 0)) != NULL)
452 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
453 return size;
454 else
455 size++;
457 else
458 size++;
460 return size;
463 /* Return prompt character of specified node. */
464 const char *
465 cmd_prompt (enum node_type node)
467 struct cmd_node *cnode;
469 cnode = vector_slot (cmdvec, node);
470 return cnode->prompt;
473 /* Install a command into a node. */
474 void
475 install_element (enum node_type ntype, struct cmd_element *cmd)
477 struct cmd_node *cnode;
479 /* cmd_init hasn't been called */
480 if (!cmdvec)
481 return;
483 cnode = vector_slot (cmdvec, ntype);
485 if (cnode == NULL)
487 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
488 ntype);
489 exit (1);
492 vector_set (cnode->cmd_vector, cmd);
494 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
495 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
498 static unsigned char itoa64[] =
499 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
501 static void
502 to64(char *s, long v, int n)
504 while (--n >= 0)
506 *s++ = itoa64[v&0x3f];
507 v >>= 6;
511 static char *
512 zencrypt (const char *passwd)
514 char salt[6];
515 struct timeval tv;
516 char *crypt (const char *, const char *);
518 gettimeofday(&tv,0);
520 to64(&salt[0], random(), 3);
521 to64(&salt[3], tv.tv_usec, 3);
522 salt[5] = '\0';
524 return crypt (passwd, salt);
527 /* This function write configuration of this host. */
528 static int
529 config_write_host (struct vty *vty)
531 if (host.name)
532 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
534 if (host.encrypt)
536 if (host.password_encrypt)
537 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
538 if (host.enable_encrypt)
539 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
541 else
543 if (host.password)
544 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
545 if (host.enable)
546 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
549 if (zlog_default->default_lvl != LOG_DEBUG)
551 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
552 VTY_NEWLINE);
553 vty_out (vty, "log trap %s%s",
554 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
557 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
559 vty_out (vty, "log file %s", host.logfile);
560 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
561 vty_out (vty, " %s",
562 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
563 vty_out (vty, "%s", VTY_NEWLINE);
566 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
568 vty_out (vty, "log stdout");
569 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
572 vty_out (vty, "%s", VTY_NEWLINE);
575 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
576 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
577 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
578 vty_out(vty,"log monitor %s%s",
579 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
581 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
583 vty_out (vty, "log syslog");
584 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
585 vty_out (vty, " %s",
586 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
587 vty_out (vty, "%s", VTY_NEWLINE);
590 if (zlog_default->facility != LOG_DAEMON)
591 vty_out (vty, "log facility %s%s",
592 facility_name(zlog_default->facility), VTY_NEWLINE);
594 if (zlog_default->record_priority == 1)
595 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
597 if (zlog_default->timestamp_precision > 0)
598 vty_out (vty, "log timestamp precision %d%s",
599 zlog_default->timestamp_precision, VTY_NEWLINE);
601 if (host.advanced)
602 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
604 if (host.encrypt)
605 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
607 if (host.lines >= 0)
608 vty_out (vty, "service terminal-length %d%s", host.lines,
609 VTY_NEWLINE);
611 if (host.motdfile)
612 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
613 else if (! host.motd)
614 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
616 return 1;
619 /* Utility function for getting command vector. */
620 static vector
621 cmd_node_vector (vector v, enum node_type ntype)
623 struct cmd_node *cnode = vector_slot (v, ntype);
624 return cnode->cmd_vector;
627 #if 0
628 /* Filter command vector by symbol. This function is not actually used;
629 * should it be deleted? */
630 static int
631 cmd_filter_by_symbol (char *command, char *symbol)
633 int i, lim;
635 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
637 i = 0;
638 lim = strlen (command);
639 while (i < lim)
641 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
642 return 1;
643 i++;
645 return 0;
647 if (strcmp (symbol, "STRING") == 0)
649 i = 0;
650 lim = strlen (command);
651 while (i < lim)
653 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
654 return 1;
655 i++;
657 return 0;
659 if (strcmp (symbol, "IFNAME") == 0)
661 i = 0;
662 lim = strlen (command);
663 while (i < lim)
665 if (! isalnum ((int) command[i]))
666 return 1;
667 i++;
669 return 0;
671 return 0;
673 #endif
675 /* Completion match types. */
676 enum match_type
678 no_match,
679 extend_match,
680 ipv4_prefix_match,
681 ipv4_match,
682 ipv6_prefix_match,
683 ipv6_match,
684 range_match,
685 vararg_match,
686 partly_match,
687 exact_match
690 static enum match_type
691 cmd_ipv4_match (const char *str)
693 const char *sp;
694 int dots = 0, nums = 0;
695 char buf[4];
697 if (str == NULL)
698 return partly_match;
700 for (;;)
702 memset (buf, 0, sizeof (buf));
703 sp = str;
704 while (*str != '\0')
706 if (*str == '.')
708 if (dots >= 3)
709 return no_match;
711 if (*(str + 1) == '.')
712 return no_match;
714 if (*(str + 1) == '\0')
715 return partly_match;
717 dots++;
718 break;
720 if (!isdigit ((int) *str))
721 return no_match;
723 str++;
726 if (str - sp > 3)
727 return no_match;
729 strncpy (buf, sp, str - sp);
730 if (atoi (buf) > 255)
731 return no_match;
733 nums++;
735 if (*str == '\0')
736 break;
738 str++;
741 if (nums < 4)
742 return partly_match;
744 return exact_match;
747 static enum match_type
748 cmd_ipv4_prefix_match (const char *str)
750 const char *sp;
751 int dots = 0;
752 char buf[4];
754 if (str == NULL)
755 return partly_match;
757 for (;;)
759 memset (buf, 0, sizeof (buf));
760 sp = str;
761 while (*str != '\0' && *str != '/')
763 if (*str == '.')
765 if (dots == 3)
766 return no_match;
768 if (*(str + 1) == '.' || *(str + 1) == '/')
769 return no_match;
771 if (*(str + 1) == '\0')
772 return partly_match;
774 dots++;
775 break;
778 if (!isdigit ((int) *str))
779 return no_match;
781 str++;
784 if (str - sp > 3)
785 return no_match;
787 strncpy (buf, sp, str - sp);
788 if (atoi (buf) > 255)
789 return no_match;
791 if (dots == 3)
793 if (*str == '/')
795 if (*(str + 1) == '\0')
796 return partly_match;
798 str++;
799 break;
801 else if (*str == '\0')
802 return partly_match;
805 if (*str == '\0')
806 return partly_match;
808 str++;
811 sp = str;
812 while (*str != '\0')
814 if (!isdigit ((int) *str))
815 return no_match;
817 str++;
820 if (atoi (sp) > 32)
821 return no_match;
823 return exact_match;
826 #define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
827 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
828 #define STATE_START 1
829 #define STATE_COLON 2
830 #define STATE_DOUBLE 3
831 #define STATE_ADDR 4
832 #define STATE_DOT 5
833 #define STATE_SLASH 6
834 #define STATE_MASK 7
836 #ifdef HAVE_IPV6
838 static enum match_type
839 cmd_ipv6_match (const char *str)
841 int state = STATE_START;
842 int colons = 0, nums = 0, double_colon = 0;
843 const char *sp = NULL;
844 struct sockaddr_in6 sin6_dummy;
845 int ret;
847 if (str == NULL)
848 return partly_match;
850 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
851 return no_match;
853 /* use inet_pton that has a better support,
854 * for example inet_pton can support the automatic addresses:
855 * ::1.2.3.4
857 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
859 if (ret == 1)
860 return exact_match;
862 while (*str != '\0')
864 switch (state)
866 case STATE_START:
867 if (*str == ':')
869 if (*(str + 1) != ':' && *(str + 1) != '\0')
870 return no_match;
871 colons--;
872 state = STATE_COLON;
874 else
876 sp = str;
877 state = STATE_ADDR;
880 continue;
881 case STATE_COLON:
882 colons++;
883 if (*(str + 1) == ':')
884 state = STATE_DOUBLE;
885 else
887 sp = str + 1;
888 state = STATE_ADDR;
890 break;
891 case STATE_DOUBLE:
892 if (double_colon)
893 return no_match;
895 if (*(str + 1) == ':')
896 return no_match;
897 else
899 if (*(str + 1) != '\0')
900 colons++;
901 sp = str + 1;
902 state = STATE_ADDR;
905 double_colon++;
906 nums++;
907 break;
908 case STATE_ADDR:
909 if (*(str + 1) == ':' || *(str + 1) == '\0')
911 if (str - sp > 3)
912 return no_match;
914 nums++;
915 state = STATE_COLON;
917 if (*(str + 1) == '.')
918 state = STATE_DOT;
919 break;
920 case STATE_DOT:
921 state = STATE_ADDR;
922 break;
923 default:
924 break;
927 if (nums > 8)
928 return no_match;
930 if (colons > 7)
931 return no_match;
933 str++;
936 #if 0
937 if (nums < 11)
938 return partly_match;
939 #endif /* 0 */
941 return exact_match;
944 static enum match_type
945 cmd_ipv6_prefix_match (const char *str)
947 int state = STATE_START;
948 int colons = 0, nums = 0, double_colon = 0;
949 int mask;
950 const char *sp = NULL;
951 char *endptr = NULL;
953 if (str == NULL)
954 return partly_match;
956 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
957 return no_match;
959 while (*str != '\0' && state != STATE_MASK)
961 switch (state)
963 case STATE_START:
964 if (*str == ':')
966 if (*(str + 1) != ':' && *(str + 1) != '\0')
967 return no_match;
968 colons--;
969 state = STATE_COLON;
971 else
973 sp = str;
974 state = STATE_ADDR;
977 continue;
978 case STATE_COLON:
979 colons++;
980 if (*(str + 1) == '/')
981 return no_match;
982 else if (*(str + 1) == ':')
983 state = STATE_DOUBLE;
984 else
986 sp = str + 1;
987 state = STATE_ADDR;
989 break;
990 case STATE_DOUBLE:
991 if (double_colon)
992 return no_match;
994 if (*(str + 1) == ':')
995 return no_match;
996 else
998 if (*(str + 1) != '\0' && *(str + 1) != '/')
999 colons++;
1000 sp = str + 1;
1002 if (*(str + 1) == '/')
1003 state = STATE_SLASH;
1004 else
1005 state = STATE_ADDR;
1008 double_colon++;
1009 nums += 1;
1010 break;
1011 case STATE_ADDR:
1012 if (*(str + 1) == ':' || *(str + 1) == '.'
1013 || *(str + 1) == '\0' || *(str + 1) == '/')
1015 if (str - sp > 3)
1016 return no_match;
1018 for (; sp <= str; sp++)
1019 if (*sp == '/')
1020 return no_match;
1022 nums++;
1024 if (*(str + 1) == ':')
1025 state = STATE_COLON;
1026 else if (*(str + 1) == '.')
1027 state = STATE_DOT;
1028 else if (*(str + 1) == '/')
1029 state = STATE_SLASH;
1031 break;
1032 case STATE_DOT:
1033 state = STATE_ADDR;
1034 break;
1035 case STATE_SLASH:
1036 if (*(str + 1) == '\0')
1037 return partly_match;
1039 state = STATE_MASK;
1040 break;
1041 default:
1042 break;
1045 if (nums > 11)
1046 return no_match;
1048 if (colons > 7)
1049 return no_match;
1051 str++;
1054 if (state < STATE_MASK)
1055 return partly_match;
1057 mask = strtol (str, &endptr, 10);
1058 if (*endptr != '\0')
1059 return no_match;
1061 if (mask < 0 || mask > 128)
1062 return no_match;
1064 /* I don't know why mask < 13 makes command match partly.
1065 Forgive me to make this comments. I Want to set static default route
1066 because of lack of function to originate default in ospf6d; sorry
1067 yasu
1068 if (mask < 13)
1069 return partly_match;
1072 return exact_match;
1075 #endif /* HAVE_IPV6 */
1077 #define DECIMAL_STRLEN_MAX 10
1079 static int
1080 cmd_range_match (const char *range, const char *str)
1082 char *p;
1083 char buf[DECIMAL_STRLEN_MAX + 1];
1084 char *endptr = NULL;
1085 unsigned long min, max, val;
1087 if (str == NULL)
1088 return 1;
1090 val = strtoul (str, &endptr, 10);
1091 if (*endptr != '\0')
1092 return 0;
1094 range++;
1095 p = strchr (range, '-');
1096 if (p == NULL)
1097 return 0;
1098 if (p - range > DECIMAL_STRLEN_MAX)
1099 return 0;
1100 strncpy (buf, range, p - range);
1101 buf[p - range] = '\0';
1102 min = strtoul (buf, &endptr, 10);
1103 if (*endptr != '\0')
1104 return 0;
1106 range = p + 1;
1107 p = strchr (range, '>');
1108 if (p == NULL)
1109 return 0;
1110 if (p - range > DECIMAL_STRLEN_MAX)
1111 return 0;
1112 strncpy (buf, range, p - range);
1113 buf[p - range] = '\0';
1114 max = strtoul (buf, &endptr, 10);
1115 if (*endptr != '\0')
1116 return 0;
1118 if (val < min || val > max)
1119 return 0;
1121 return 1;
1124 /* Make completion match and return match type flag. */
1125 static enum match_type
1126 cmd_filter_by_completion (char *command, vector v, unsigned int index)
1128 unsigned int i;
1129 const char *str;
1130 struct cmd_element *cmd_element;
1131 enum match_type match_type;
1132 vector descvec;
1133 struct desc *desc;
1135 match_type = no_match;
1137 /* If command and cmd_element string does not match set NULL to vector */
1138 for (i = 0; i < vector_active (v); i++)
1139 if ((cmd_element = vector_slot (v, i)) != NULL)
1141 if (index >= vector_active (cmd_element->strvec))
1142 vector_slot (v, i) = NULL;
1143 else
1145 unsigned int j;
1146 int matched = 0;
1148 descvec = vector_slot (cmd_element->strvec, index);
1150 for (j = 0; j < vector_active (descvec); j++)
1151 if ((desc = vector_slot (descvec, j)))
1153 str = desc->cmd;
1155 if (CMD_VARARG (str))
1157 if (match_type < vararg_match)
1158 match_type = vararg_match;
1159 matched++;
1161 else if (CMD_RANGE (str))
1163 if (cmd_range_match (str, command))
1165 if (match_type < range_match)
1166 match_type = range_match;
1168 matched++;
1171 #ifdef HAVE_IPV6
1172 else if (CMD_IPV6 (str))
1174 if (cmd_ipv6_match (command))
1176 if (match_type < ipv6_match)
1177 match_type = ipv6_match;
1179 matched++;
1182 else if (CMD_IPV6_PREFIX (str))
1184 if (cmd_ipv6_prefix_match (command))
1186 if (match_type < ipv6_prefix_match)
1187 match_type = ipv6_prefix_match;
1189 matched++;
1192 #endif /* HAVE_IPV6 */
1193 else if (CMD_IPV4 (str))
1195 if (cmd_ipv4_match (command))
1197 if (match_type < ipv4_match)
1198 match_type = ipv4_match;
1200 matched++;
1203 else if (CMD_IPV4_PREFIX (str))
1205 if (cmd_ipv4_prefix_match (command))
1207 if (match_type < ipv4_prefix_match)
1208 match_type = ipv4_prefix_match;
1209 matched++;
1212 else
1213 /* Check is this point's argument optional ? */
1214 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1216 if (match_type < extend_match)
1217 match_type = extend_match;
1218 matched++;
1220 else if (strncmp (command, str, strlen (command)) == 0)
1222 if (strcmp (command, str) == 0)
1223 match_type = exact_match;
1224 else
1226 if (match_type < partly_match)
1227 match_type = partly_match;
1229 matched++;
1232 if (!matched)
1233 vector_slot (v, i) = NULL;
1236 return match_type;
1239 /* Filter vector by command character with index. */
1240 static enum match_type
1241 cmd_filter_by_string (char *command, vector v, unsigned int index)
1243 unsigned int i;
1244 const char *str;
1245 struct cmd_element *cmd_element;
1246 enum match_type match_type;
1247 vector descvec;
1248 struct desc *desc;
1250 match_type = no_match;
1252 /* If command and cmd_element string does not match set NULL to vector */
1253 for (i = 0; i < vector_active (v); i++)
1254 if ((cmd_element = vector_slot (v, i)) != NULL)
1256 /* If given index is bigger than max string vector of command,
1257 set NULL */
1258 if (index >= vector_active (cmd_element->strvec))
1259 vector_slot (v, i) = NULL;
1260 else
1262 unsigned int j;
1263 int matched = 0;
1265 descvec = vector_slot (cmd_element->strvec, index);
1267 for (j = 0; j < vector_active (descvec); j++)
1268 if ((desc = vector_slot (descvec, j)))
1270 str = desc->cmd;
1272 if (CMD_VARARG (str))
1274 if (match_type < vararg_match)
1275 match_type = vararg_match;
1276 matched++;
1278 else if (CMD_RANGE (str))
1280 if (cmd_range_match (str, command))
1282 if (match_type < range_match)
1283 match_type = range_match;
1284 matched++;
1287 #ifdef HAVE_IPV6
1288 else if (CMD_IPV6 (str))
1290 if (cmd_ipv6_match (command) == exact_match)
1292 if (match_type < ipv6_match)
1293 match_type = ipv6_match;
1294 matched++;
1297 else if (CMD_IPV6_PREFIX (str))
1299 if (cmd_ipv6_prefix_match (command) == exact_match)
1301 if (match_type < ipv6_prefix_match)
1302 match_type = ipv6_prefix_match;
1303 matched++;
1306 #endif /* HAVE_IPV6 */
1307 else if (CMD_IPV4 (str))
1309 if (cmd_ipv4_match (command) == exact_match)
1311 if (match_type < ipv4_match)
1312 match_type = ipv4_match;
1313 matched++;
1316 else if (CMD_IPV4_PREFIX (str))
1318 if (cmd_ipv4_prefix_match (command) == exact_match)
1320 if (match_type < ipv4_prefix_match)
1321 match_type = ipv4_prefix_match;
1322 matched++;
1325 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1327 if (match_type < extend_match)
1328 match_type = extend_match;
1329 matched++;
1331 else
1333 if (strcmp (command, str) == 0)
1335 match_type = exact_match;
1336 matched++;
1340 if (!matched)
1341 vector_slot (v, i) = NULL;
1344 return match_type;
1347 /* Check ambiguous match */
1348 static int
1349 is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1351 unsigned int i;
1352 unsigned int j;
1353 const char *str = NULL;
1354 struct cmd_element *cmd_element;
1355 const char *matched = NULL;
1356 vector descvec;
1357 struct desc *desc;
1359 for (i = 0; i < vector_active (v); i++)
1360 if ((cmd_element = vector_slot (v, i)) != NULL)
1362 int match = 0;
1364 descvec = vector_slot (cmd_element->strvec, index);
1366 for (j = 0; j < vector_active (descvec); j++)
1367 if ((desc = vector_slot (descvec, j)))
1369 enum match_type ret;
1371 str = desc->cmd;
1373 switch (type)
1375 case exact_match:
1376 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1377 && strcmp (command, str) == 0)
1378 match++;
1379 break;
1380 case partly_match:
1381 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1382 && strncmp (command, str, strlen (command)) == 0)
1384 if (matched && strcmp (matched, str) != 0)
1385 return 1; /* There is ambiguous match. */
1386 else
1387 matched = str;
1388 match++;
1390 break;
1391 case range_match:
1392 if (cmd_range_match (str, command))
1394 if (matched && strcmp (matched, str) != 0)
1395 return 1;
1396 else
1397 matched = str;
1398 match++;
1400 break;
1401 #ifdef HAVE_IPV6
1402 case ipv6_match:
1403 if (CMD_IPV6 (str))
1404 match++;
1405 break;
1406 case ipv6_prefix_match:
1407 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1409 if (ret == partly_match)
1410 return 2; /* There is incomplete match. */
1412 match++;
1414 break;
1415 #endif /* HAVE_IPV6 */
1416 case ipv4_match:
1417 if (CMD_IPV4 (str))
1418 match++;
1419 break;
1420 case ipv4_prefix_match:
1421 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1423 if (ret == partly_match)
1424 return 2; /* There is incomplete match. */
1426 match++;
1428 break;
1429 case extend_match:
1430 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1431 match++;
1432 break;
1433 case no_match:
1434 default:
1435 break;
1438 if (!match)
1439 vector_slot (v, i) = NULL;
1441 return 0;
1444 /* If src matches dst return dst string, otherwise return NULL */
1445 static const char *
1446 cmd_entry_function (const char *src, const char *dst)
1448 /* Skip variable arguments. */
1449 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1450 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1451 return NULL;
1453 /* In case of 'command \t', given src is NULL string. */
1454 if (src == NULL)
1455 return dst;
1457 /* Matched with input string. */
1458 if (strncmp (src, dst, strlen (src)) == 0)
1459 return dst;
1461 return NULL;
1464 /* If src matches dst return dst string, otherwise return NULL */
1465 /* This version will return the dst string always if it is
1466 CMD_VARIABLE for '?' key processing */
1467 static const char *
1468 cmd_entry_function_desc (const char *src, const char *dst)
1470 if (CMD_VARARG (dst))
1471 return dst;
1473 if (CMD_RANGE (dst))
1475 if (cmd_range_match (dst, src))
1476 return dst;
1477 else
1478 return NULL;
1481 #ifdef HAVE_IPV6
1482 if (CMD_IPV6 (dst))
1484 if (cmd_ipv6_match (src))
1485 return dst;
1486 else
1487 return NULL;
1490 if (CMD_IPV6_PREFIX (dst))
1492 if (cmd_ipv6_prefix_match (src))
1493 return dst;
1494 else
1495 return NULL;
1497 #endif /* HAVE_IPV6 */
1499 if (CMD_IPV4 (dst))
1501 if (cmd_ipv4_match (src))
1502 return dst;
1503 else
1504 return NULL;
1507 if (CMD_IPV4_PREFIX (dst))
1509 if (cmd_ipv4_prefix_match (src))
1510 return dst;
1511 else
1512 return NULL;
1515 /* Optional or variable commands always match on '?' */
1516 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1517 return dst;
1519 /* In case of 'command \t', given src is NULL string. */
1520 if (src == NULL)
1521 return dst;
1523 if (strncmp (src, dst, strlen (src)) == 0)
1524 return dst;
1525 else
1526 return NULL;
1529 /* Check same string element existence. If it isn't there return
1530 1. */
1531 static int
1532 cmd_unique_string (vector v, const char *str)
1534 unsigned int i;
1535 char *match;
1537 for (i = 0; i < vector_active (v); i++)
1538 if ((match = vector_slot (v, i)) != NULL)
1539 if (strcmp (match, str) == 0)
1540 return 0;
1541 return 1;
1544 /* Compare string to description vector. If there is same string
1545 return 1 else return 0. */
1546 static int
1547 desc_unique_string (vector v, const char *str)
1549 unsigned int i;
1550 struct desc *desc;
1552 for (i = 0; i < vector_active (v); i++)
1553 if ((desc = vector_slot (v, i)) != NULL)
1554 if (strcmp (desc->cmd, str) == 0)
1555 return 1;
1556 return 0;
1559 static int
1560 cmd_try_do_shortcut (enum node_type node, char* first_word) {
1561 if ( first_word != NULL &&
1562 node != AUTH_NODE &&
1563 node != VIEW_NODE &&
1564 node != AUTH_ENABLE_NODE &&
1565 node != ENABLE_NODE &&
1566 0 == strcmp( "do", first_word ) )
1567 return 1;
1568 return 0;
1571 /* '?' describe command support. */
1572 static vector
1573 cmd_describe_command_real (vector vline, struct vty *vty, int *status)
1575 unsigned int i;
1576 vector cmd_vector;
1577 #define INIT_MATCHVEC_SIZE 10
1578 vector matchvec;
1579 struct cmd_element *cmd_element;
1580 unsigned int index;
1581 int ret;
1582 enum match_type match;
1583 char *command;
1584 static struct desc desc_cr = { "<cr>", "" };
1586 /* Set index. */
1587 if (vector_active (vline) == 0)
1589 *status = CMD_ERR_NO_MATCH;
1590 return NULL;
1592 else
1593 index = vector_active (vline) - 1;
1595 /* Make copy vector of current node's command vector. */
1596 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1598 /* Prepare match vector */
1599 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1601 /* Filter commands. */
1602 /* Only words precedes current word will be checked in this loop. */
1603 for (i = 0; i < index; i++)
1604 if ((command = vector_slot (vline, i)))
1606 match = cmd_filter_by_completion (command, cmd_vector, i);
1608 if (match == vararg_match)
1610 struct cmd_element *cmd_element;
1611 vector descvec;
1612 unsigned int j, k;
1614 for (j = 0; j < vector_active (cmd_vector); j++)
1615 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
1616 && (vector_active (cmd_element->strvec)))
1618 descvec = vector_slot (cmd_element->strvec,
1619 vector_active (cmd_element->strvec) - 1);
1620 for (k = 0; k < vector_active (descvec); k++)
1622 struct desc *desc = vector_slot (descvec, k);
1623 vector_set (matchvec, desc);
1627 vector_set (matchvec, &desc_cr);
1628 vector_free (cmd_vector);
1630 return matchvec;
1633 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1635 vector_free (cmd_vector);
1636 vector_free (matchvec);
1637 *status = CMD_ERR_AMBIGUOUS;
1638 return NULL;
1640 else if (ret == 2)
1642 vector_free (cmd_vector);
1643 vector_free (matchvec);
1644 *status = CMD_ERR_NO_MATCH;
1645 return NULL;
1649 /* Prepare match vector */
1650 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1652 /* Make sure that cmd_vector is filtered based on current word */
1653 command = vector_slot (vline, index);
1654 if (command)
1655 match = cmd_filter_by_completion (command, cmd_vector, index);
1657 /* Make description vector. */
1658 for (i = 0; i < vector_active (cmd_vector); i++)
1659 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1661 const char *string = NULL;
1662 vector strvec = cmd_element->strvec;
1664 /* if command is NULL, index may be equal to vector_active */
1665 if (command && index >= vector_active (strvec))
1666 vector_slot (cmd_vector, i) = NULL;
1667 else
1669 /* Check if command is completed. */
1670 if (command == NULL && index == vector_active (strvec))
1672 string = "<cr>";
1673 if (!desc_unique_string (matchvec, string))
1674 vector_set (matchvec, &desc_cr);
1676 else
1678 unsigned int j;
1679 vector descvec = vector_slot (strvec, index);
1680 struct desc *desc;
1682 for (j = 0; j < vector_active (descvec); j++)
1683 if ((desc = vector_slot (descvec, j)))
1685 string = cmd_entry_function_desc (command, desc->cmd);
1686 if (string)
1688 /* Uniqueness check */
1689 if (!desc_unique_string (matchvec, string))
1690 vector_set (matchvec, desc);
1696 vector_free (cmd_vector);
1698 if (vector_slot (matchvec, 0) == NULL)
1700 vector_free (matchvec);
1701 *status = CMD_ERR_NO_MATCH;
1702 return NULL;
1705 *status = CMD_SUCCESS;
1706 return matchvec;
1709 vector
1710 cmd_describe_command (vector vline, struct vty *vty, int *status)
1712 vector ret;
1714 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1716 enum node_type onode;
1717 vector shifted_vline;
1718 unsigned int index;
1720 onode = vty->node;
1721 vty->node = ENABLE_NODE;
1722 /* We can try it on enable node, cos' the vty is authenticated */
1724 shifted_vline = vector_init (vector_count(vline));
1725 /* use memcpy? */
1726 for (index = 1; index < vector_active (vline); index++)
1728 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1731 ret = cmd_describe_command_real (shifted_vline, vty, status);
1733 vector_free(shifted_vline);
1734 vty->node = onode;
1735 return ret;
1739 return cmd_describe_command_real (vline, vty, status);
1743 /* Check LCD of matched command. */
1744 static int
1745 cmd_lcd (char **matched)
1747 int i;
1748 int j;
1749 int lcd = -1;
1750 char *s1, *s2;
1751 char c1, c2;
1753 if (matched[0] == NULL || matched[1] == NULL)
1754 return 0;
1756 for (i = 1; matched[i] != NULL; i++)
1758 s1 = matched[i - 1];
1759 s2 = matched[i];
1761 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1762 if (c1 != c2)
1763 break;
1765 if (lcd < 0)
1766 lcd = j;
1767 else
1769 if (lcd > j)
1770 lcd = j;
1773 return lcd;
1776 /* Command line completion support. */
1777 static char **
1778 cmd_complete_command_real (vector vline, struct vty *vty, int *status)
1780 unsigned int i;
1781 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1782 #define INIT_MATCHVEC_SIZE 10
1783 vector matchvec;
1784 struct cmd_element *cmd_element;
1785 unsigned int index;
1786 char **match_str;
1787 struct desc *desc;
1788 vector descvec;
1789 char *command;
1790 int lcd;
1792 if (vector_active (vline) == 0)
1794 vector_free (cmd_vector);
1795 *status = CMD_ERR_NO_MATCH;
1796 return NULL;
1798 else
1799 index = vector_active (vline) - 1;
1801 /* First, filter by preceeding command string */
1802 for (i = 0; i < index; i++)
1803 if ((command = vector_slot (vline, i)))
1805 enum match_type match;
1806 int ret;
1808 /* First try completion match, if there is exactly match return 1 */
1809 match = cmd_filter_by_completion (command, cmd_vector, i);
1811 /* If there is exact match then filter ambiguous match else check
1812 ambiguousness. */
1813 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1815 vector_free (cmd_vector);
1816 *status = CMD_ERR_AMBIGUOUS;
1817 return NULL;
1820 else if (ret == 2)
1822 vector_free (cmd_vector);
1823 *status = CMD_ERR_NO_MATCH;
1824 return NULL;
1829 /* Prepare match vector. */
1830 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1832 /* Now we got into completion */
1833 for (i = 0; i < vector_active (cmd_vector); i++)
1834 if ((cmd_element = vector_slot (cmd_vector, i)))
1836 const char *string;
1837 vector strvec = cmd_element->strvec;
1839 /* Check field length */
1840 if (index >= vector_active (strvec))
1841 vector_slot (cmd_vector, i) = NULL;
1842 else
1844 unsigned int j;
1846 descvec = vector_slot (strvec, index);
1847 for (j = 0; j < vector_active (descvec); j++)
1848 if ((desc = vector_slot (descvec, j)))
1850 if ((string =
1851 cmd_entry_function (vector_slot (vline, index),
1852 desc->cmd)))
1853 if (cmd_unique_string (matchvec, string))
1854 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1859 /* We don't need cmd_vector any more. */
1860 vector_free (cmd_vector);
1862 /* No matched command */
1863 if (vector_slot (matchvec, 0) == NULL)
1865 vector_free (matchvec);
1867 /* In case of 'command \t' pattern. Do you need '?' command at
1868 the end of the line. */
1869 if (vector_slot (vline, index) == '\0')
1870 *status = CMD_ERR_NOTHING_TODO;
1871 else
1872 *status = CMD_ERR_NO_MATCH;
1873 return NULL;
1876 /* Only one matched */
1877 if (vector_slot (matchvec, 1) == NULL)
1879 match_str = (char **) matchvec->index;
1880 vector_only_wrapper_free (matchvec);
1881 *status = CMD_COMPLETE_FULL_MATCH;
1882 return match_str;
1884 /* Make it sure last element is NULL. */
1885 vector_set (matchvec, NULL);
1887 /* Check LCD of matched strings. */
1888 if (vector_slot (vline, index) != NULL)
1890 lcd = cmd_lcd ((char **) matchvec->index);
1892 if (lcd)
1894 int len = strlen (vector_slot (vline, index));
1896 if (len < lcd)
1898 char *lcdstr;
1900 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
1901 memcpy (lcdstr, matchvec->index[0], lcd);
1902 lcdstr[lcd] = '\0';
1904 /* match_str = (char **) &lcdstr; */
1906 /* Free matchvec. */
1907 for (i = 0; i < vector_active (matchvec); i++)
1909 if (vector_slot (matchvec, i))
1910 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
1912 vector_free (matchvec);
1914 /* Make new matchvec. */
1915 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1916 vector_set (matchvec, lcdstr);
1917 match_str = (char **) matchvec->index;
1918 vector_only_wrapper_free (matchvec);
1920 *status = CMD_COMPLETE_MATCH;
1921 return match_str;
1926 match_str = (char **) matchvec->index;
1927 vector_only_wrapper_free (matchvec);
1928 *status = CMD_COMPLETE_LIST_MATCH;
1929 return match_str;
1932 char **
1933 cmd_complete_command (vector vline, struct vty *vty, int *status)
1935 char **ret;
1937 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1939 enum node_type onode;
1940 vector shifted_vline;
1941 unsigned int index;
1943 onode = vty->node;
1944 vty->node = ENABLE_NODE;
1945 /* We can try it on enable node, cos' the vty is authenticated */
1947 shifted_vline = vector_init (vector_count(vline));
1948 /* use memcpy? */
1949 for (index = 1; index < vector_active (vline); index++)
1951 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1954 ret = cmd_complete_command_real (shifted_vline, vty, status);
1956 vector_free(shifted_vline);
1957 vty->node = onode;
1958 return ret;
1962 return cmd_complete_command_real (vline, vty, status);
1965 /* return parent node */
1966 /* MUST eventually converge on CONFIG_NODE */
1967 enum node_type
1968 node_parent ( enum node_type node )
1970 enum node_type ret;
1972 assert (node > CONFIG_NODE);
1974 switch (node)
1976 case BGP_VPNV4_NODE:
1977 case BGP_IPV4_NODE:
1978 case BGP_IPV4M_NODE:
1979 case BGP_IPV6_NODE:
1980 case BGP_IPV6M_NODE:
1981 ret = BGP_NODE;
1982 break;
1983 case KEYCHAIN_KEY_NODE:
1984 ret = KEYCHAIN_NODE;
1985 break;
1986 default:
1987 ret = CONFIG_NODE;
1990 return ret;
1993 /* Execute command by argument vline vector. */
1994 static int
1995 cmd_execute_command_real (vector vline, struct vty *vty,
1996 struct cmd_element **cmd)
1998 unsigned int i;
1999 unsigned int index;
2000 vector cmd_vector;
2001 struct cmd_element *cmd_element;
2002 struct cmd_element *matched_element;
2003 unsigned int matched_count, incomplete_count;
2004 int argc;
2005 const char *argv[CMD_ARGC_MAX];
2006 enum match_type match = 0;
2007 int varflag;
2008 char *command;
2010 /* Make copy of command elements. */
2011 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2013 for (index = 0; index < vector_active (vline); index++)
2014 if ((command = vector_slot (vline, index)))
2016 int ret;
2018 match = cmd_filter_by_completion (command, cmd_vector, index);
2020 if (match == vararg_match)
2021 break;
2023 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2025 if (ret == 1)
2027 vector_free (cmd_vector);
2028 return CMD_ERR_AMBIGUOUS;
2030 else if (ret == 2)
2032 vector_free (cmd_vector);
2033 return CMD_ERR_NO_MATCH;
2037 /* Check matched count. */
2038 matched_element = NULL;
2039 matched_count = 0;
2040 incomplete_count = 0;
2042 for (i = 0; i < vector_active (cmd_vector); i++)
2043 if ((cmd_element = vector_slot (cmd_vector, i)))
2045 if (match == vararg_match || index >= cmd_element->cmdsize)
2047 matched_element = cmd_element;
2048 #if 0
2049 printf ("DEBUG: %s\n", cmd_element->string);
2050 #endif
2051 matched_count++;
2053 else
2055 incomplete_count++;
2059 /* Finish of using cmd_vector. */
2060 vector_free (cmd_vector);
2062 /* To execute command, matched_count must be 1. */
2063 if (matched_count == 0)
2065 if (incomplete_count)
2066 return CMD_ERR_INCOMPLETE;
2067 else
2068 return CMD_ERR_NO_MATCH;
2071 if (matched_count > 1)
2072 return CMD_ERR_AMBIGUOUS;
2074 /* Argument treatment */
2075 varflag = 0;
2076 argc = 0;
2078 for (i = 0; i < vector_active (vline); i++)
2080 if (varflag)
2081 argv[argc++] = vector_slot (vline, i);
2082 else
2084 vector descvec = vector_slot (matched_element->strvec, i);
2086 if (vector_active (descvec) == 1)
2088 struct desc *desc = vector_slot (descvec, 0);
2090 if (CMD_VARARG (desc->cmd))
2091 varflag = 1;
2093 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
2094 argv[argc++] = vector_slot (vline, i);
2096 else
2097 argv[argc++] = vector_slot (vline, i);
2100 if (argc >= CMD_ARGC_MAX)
2101 return CMD_ERR_EXEED_ARGC_MAX;
2104 /* For vtysh execution. */
2105 if (cmd)
2106 *cmd = matched_element;
2108 if (matched_element->daemon)
2109 return CMD_SUCCESS_DAEMON;
2111 /* Execute matched command. */
2112 return (*matched_element->func) (matched_element, vty, argc, argv);
2116 cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2117 int vtysh) {
2118 int ret, saved_ret, tried = 0;
2119 enum node_type onode, try_node;
2121 onode = try_node = vty->node;
2123 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2125 vector shifted_vline;
2126 unsigned int index;
2128 vty->node = ENABLE_NODE;
2129 /* We can try it on enable node, cos' the vty is authenticated */
2131 shifted_vline = vector_init (vector_count(vline));
2132 /* use memcpy? */
2133 for (index = 1; index < vector_active (vline); index++)
2135 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2138 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2140 vector_free(shifted_vline);
2141 vty->node = onode;
2142 return ret;
2146 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
2148 if (vtysh)
2149 return saved_ret;
2151 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
2152 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
2153 && vty->node > CONFIG_NODE )
2155 try_node = node_parent(try_node);
2156 vty->node = try_node;
2157 ret = cmd_execute_command_real (vline, vty, cmd);
2158 tried = 1;
2159 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
2161 /* succesfull command, leave the node as is */
2162 return ret;
2165 /* no command succeeded, reset the vty to the original node and
2166 return the error for this node */
2167 if ( tried )
2168 vty->node = onode;
2169 return saved_ret;
2172 /* Execute command by argument readline. */
2174 cmd_execute_command_strict (vector vline, struct vty *vty,
2175 struct cmd_element **cmd)
2177 unsigned int i;
2178 unsigned int index;
2179 vector cmd_vector;
2180 struct cmd_element *cmd_element;
2181 struct cmd_element *matched_element;
2182 unsigned int matched_count, incomplete_count;
2183 int argc;
2184 const char *argv[CMD_ARGC_MAX];
2185 int varflag;
2186 enum match_type match = 0;
2187 char *command;
2189 /* Make copy of command element */
2190 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2192 for (index = 0; index < vector_active (vline); index++)
2193 if ((command = vector_slot (vline, index)))
2195 int ret;
2197 match = cmd_filter_by_string (vector_slot (vline, index),
2198 cmd_vector, index);
2200 /* If command meets '.VARARG' then finish matching. */
2201 if (match == vararg_match)
2202 break;
2204 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2205 if (ret == 1)
2207 vector_free (cmd_vector);
2208 return CMD_ERR_AMBIGUOUS;
2210 if (ret == 2)
2212 vector_free (cmd_vector);
2213 return CMD_ERR_NO_MATCH;
2217 /* Check matched count. */
2218 matched_element = NULL;
2219 matched_count = 0;
2220 incomplete_count = 0;
2221 for (i = 0; i < vector_active (cmd_vector); i++)
2222 if (vector_slot (cmd_vector, i) != NULL)
2224 cmd_element = vector_slot (cmd_vector, i);
2226 if (match == vararg_match || index >= cmd_element->cmdsize)
2228 matched_element = cmd_element;
2229 matched_count++;
2231 else
2232 incomplete_count++;
2235 /* Finish of using cmd_vector. */
2236 vector_free (cmd_vector);
2238 /* To execute command, matched_count must be 1. */
2239 if (matched_count == 0)
2241 if (incomplete_count)
2242 return CMD_ERR_INCOMPLETE;
2243 else
2244 return CMD_ERR_NO_MATCH;
2247 if (matched_count > 1)
2248 return CMD_ERR_AMBIGUOUS;
2250 /* Argument treatment */
2251 varflag = 0;
2252 argc = 0;
2254 for (i = 0; i < vector_active (vline); i++)
2256 if (varflag)
2257 argv[argc++] = vector_slot (vline, i);
2258 else
2260 vector descvec = vector_slot (matched_element->strvec, i);
2262 if (vector_active (descvec) == 1)
2264 struct desc *desc = vector_slot (descvec, 0);
2266 if (CMD_VARARG (desc->cmd))
2267 varflag = 1;
2269 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
2270 argv[argc++] = vector_slot (vline, i);
2272 else
2273 argv[argc++] = vector_slot (vline, i);
2276 if (argc >= CMD_ARGC_MAX)
2277 return CMD_ERR_EXEED_ARGC_MAX;
2280 /* For vtysh execution. */
2281 if (cmd)
2282 *cmd = matched_element;
2284 if (matched_element->daemon)
2285 return CMD_SUCCESS_DAEMON;
2287 /* Now execute matched command */
2288 return (*matched_element->func) (matched_element, vty, argc, argv);
2291 /* Configration make from file. */
2293 config_from_file (struct vty *vty, FILE *fp)
2295 int ret;
2296 vector vline;
2298 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2300 vline = cmd_make_strvec (vty->buf);
2302 /* In case of comment line */
2303 if (vline == NULL)
2304 continue;
2305 /* Execute configuration command : this is strict match */
2306 ret = cmd_execute_command_strict (vline, vty, NULL);
2308 /* Try again with setting node to CONFIG_NODE */
2309 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2310 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2312 vty->node = node_parent(vty->node);
2313 ret = cmd_execute_command_strict (vline, vty, NULL);
2316 cmd_free_strvec (vline);
2318 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2319 && ret != CMD_ERR_NOTHING_TODO)
2320 return ret;
2322 return CMD_SUCCESS;
2325 /* Configration from terminal */
2326 DEFUN (config_terminal,
2327 config_terminal_cmd,
2328 "configure terminal",
2329 "Configuration from vty interface\n"
2330 "Configuration terminal\n")
2332 if (vty_config_lock (vty))
2333 vty->node = CONFIG_NODE;
2334 else
2336 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2337 return CMD_WARNING;
2339 return CMD_SUCCESS;
2342 /* Enable command */
2343 DEFUN (enable,
2344 config_enable_cmd,
2345 "enable",
2346 "Turn on privileged mode command\n")
2348 /* If enable password is NULL, change to ENABLE_NODE */
2349 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2350 vty->type == VTY_SHELL_SERV)
2351 vty->node = ENABLE_NODE;
2352 else
2353 vty->node = AUTH_ENABLE_NODE;
2355 return CMD_SUCCESS;
2358 /* Disable command */
2359 DEFUN (disable,
2360 config_disable_cmd,
2361 "disable",
2362 "Turn off privileged mode command\n")
2364 if (vty->node == ENABLE_NODE)
2365 vty->node = VIEW_NODE;
2366 return CMD_SUCCESS;
2369 /* Down vty node level. */
2370 DEFUN (config_exit,
2371 config_exit_cmd,
2372 "exit",
2373 "Exit current mode and down to previous mode\n")
2375 switch (vty->node)
2377 case VIEW_NODE:
2378 case ENABLE_NODE:
2379 if (vty_shell (vty))
2380 exit (0);
2381 else
2382 vty->status = VTY_CLOSE;
2383 break;
2384 case CONFIG_NODE:
2385 vty->node = ENABLE_NODE;
2386 vty_config_unlock (vty);
2387 break;
2388 case INTERFACE_NODE:
2389 case ZEBRA_NODE:
2390 case BGP_NODE:
2391 case RIP_NODE:
2392 case RIPNG_NODE:
2393 case OSPF_NODE:
2394 case OSPF6_NODE:
2395 case ISIS_NODE:
2396 case KEYCHAIN_NODE:
2397 case MASC_NODE:
2398 case RMAP_NODE:
2399 case VTY_NODE:
2400 vty->node = CONFIG_NODE;
2401 break;
2402 case BGP_VPNV4_NODE:
2403 case BGP_IPV4_NODE:
2404 case BGP_IPV4M_NODE:
2405 case BGP_IPV6_NODE:
2406 case BGP_IPV6M_NODE:
2407 vty->node = BGP_NODE;
2408 break;
2409 case KEYCHAIN_KEY_NODE:
2410 vty->node = KEYCHAIN_NODE;
2411 break;
2412 default:
2413 break;
2415 return CMD_SUCCESS;
2418 /* quit is alias of exit. */
2419 ALIAS (config_exit,
2420 config_quit_cmd,
2421 "quit",
2422 "Exit current mode and down to previous mode\n")
2424 /* End of configuration. */
2425 DEFUN (config_end,
2426 config_end_cmd,
2427 "end",
2428 "End current mode and change to enable mode.")
2430 switch (vty->node)
2432 case VIEW_NODE:
2433 case ENABLE_NODE:
2434 /* Nothing to do. */
2435 break;
2436 case CONFIG_NODE:
2437 case INTERFACE_NODE:
2438 case ZEBRA_NODE:
2439 case RIP_NODE:
2440 case RIPNG_NODE:
2441 case BGP_NODE:
2442 case BGP_VPNV4_NODE:
2443 case BGP_IPV4_NODE:
2444 case BGP_IPV4M_NODE:
2445 case BGP_IPV6_NODE:
2446 case BGP_IPV6M_NODE:
2447 case RMAP_NODE:
2448 case OSPF_NODE:
2449 case OSPF6_NODE:
2450 case ISIS_NODE:
2451 case KEYCHAIN_NODE:
2452 case KEYCHAIN_KEY_NODE:
2453 case MASC_NODE:
2454 case VTY_NODE:
2455 vty_config_unlock (vty);
2456 vty->node = ENABLE_NODE;
2457 break;
2458 default:
2459 break;
2461 return CMD_SUCCESS;
2464 /* Show version. */
2465 DEFUN (show_version,
2466 show_version_cmd,
2467 "show version",
2468 SHOW_STR
2469 "Displays zebra version\n")
2471 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2472 VTY_NEWLINE);
2473 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
2475 return CMD_SUCCESS;
2478 /* Help display function for all node. */
2479 DEFUN (config_help,
2480 config_help_cmd,
2481 "help",
2482 "Description of the interactive help system\n")
2484 vty_out (vty,
2485 "Quagga VTY provides advanced help feature. When you need help,%s\
2486 anytime at the command line please press '?'.%s\
2488 If nothing matches, the help list will be empty and you must backup%s\
2489 until entering a '?' shows the available options.%s\
2490 Two styles of help are provided:%s\
2491 1. Full help is available when you are ready to enter a%s\
2492 command argument (e.g. 'show ?') and describes each possible%s\
2493 argument.%s\
2494 2. Partial help is provided when an abbreviated argument is entered%s\
2495 and you want to know what arguments match the input%s\
2496 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2497 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2498 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2499 return CMD_SUCCESS;
2502 /* Help display function for all node. */
2503 DEFUN (config_list,
2504 config_list_cmd,
2505 "list",
2506 "Print command list\n")
2508 unsigned int i;
2509 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2510 struct cmd_element *cmd;
2512 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
2513 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2514 && !(cmd->attr == CMD_ATTR_DEPRECATED
2515 || cmd->attr == CMD_ATTR_HIDDEN))
2516 vty_out (vty, " %s%s", cmd->string,
2517 VTY_NEWLINE);
2518 return CMD_SUCCESS;
2521 /* Write current configuration into file. */
2522 DEFUN (config_write_file,
2523 config_write_file_cmd,
2524 "write file",
2525 "Write running configuration to memory, network, or terminal\n"
2526 "Write to configuration file\n")
2528 unsigned int i;
2529 int fd;
2530 struct cmd_node *node;
2531 char *config_file;
2532 char *config_file_tmp = NULL;
2533 char *config_file_sav = NULL;
2534 int ret = CMD_WARNING;
2535 struct vty *file_vty;
2537 /* Check and see if we are operating under vtysh configuration */
2538 if (host.config == NULL)
2540 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2541 VTY_NEWLINE);
2542 return CMD_WARNING;
2545 /* Get filename. */
2546 config_file = host.config;
2548 config_file_sav =
2549 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2550 strcpy (config_file_sav, config_file);
2551 strcat (config_file_sav, CONF_BACKUP_EXT);
2554 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
2555 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2557 /* Open file to configuration write. */
2558 fd = mkstemp (config_file_tmp);
2559 if (fd < 0)
2561 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2562 VTY_NEWLINE);
2563 goto finished;
2566 /* Make vty for configuration file. */
2567 file_vty = vty_new ();
2568 file_vty->fd = fd;
2569 file_vty->type = VTY_FILE;
2571 /* Config file header print. */
2572 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2573 vty_time_print (file_vty, 1);
2574 vty_out (file_vty, "!\n");
2576 for (i = 0; i < vector_active (cmdvec); i++)
2577 if ((node = vector_slot (cmdvec, i)) && node->func)
2579 if ((*node->func) (file_vty))
2580 vty_out (file_vty, "!\n");
2582 vty_close (file_vty);
2584 if (unlink (config_file_sav) != 0)
2585 if (errno != ENOENT)
2587 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2588 VTY_NEWLINE);
2589 goto finished;
2591 if (link (config_file, config_file_sav) != 0)
2593 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2594 VTY_NEWLINE);
2595 goto finished;
2597 sync ();
2598 if (unlink (config_file) != 0)
2600 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2601 VTY_NEWLINE);
2602 goto finished;
2604 if (link (config_file_tmp, config_file) != 0)
2606 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2607 VTY_NEWLINE);
2608 goto finished;
2610 sync ();
2612 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2614 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
2615 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
2616 goto finished;
2619 vty_out (vty, "Configuration saved to %s%s", config_file,
2620 VTY_NEWLINE);
2621 ret = CMD_SUCCESS;
2623 finished:
2624 unlink (config_file_tmp);
2625 XFREE (MTYPE_TMP, config_file_tmp);
2626 XFREE (MTYPE_TMP, config_file_sav);
2627 return ret;
2630 ALIAS (config_write_file,
2631 config_write_cmd,
2632 "write",
2633 "Write running configuration to memory, network, or terminal\n")
2635 ALIAS (config_write_file,
2636 config_write_memory_cmd,
2637 "write memory",
2638 "Write running configuration to memory, network, or terminal\n"
2639 "Write configuration to the file (same as write file)\n")
2641 ALIAS (config_write_file,
2642 copy_runningconfig_startupconfig_cmd,
2643 "copy running-config startup-config",
2644 "Copy configuration\n"
2645 "Copy running config to... \n"
2646 "Copy running config to startup config (same as write file)\n")
2648 /* Write current configuration into the terminal. */
2649 DEFUN (config_write_terminal,
2650 config_write_terminal_cmd,
2651 "write terminal",
2652 "Write running configuration to memory, network, or terminal\n"
2653 "Write to terminal\n")
2655 unsigned int i;
2656 struct cmd_node *node;
2658 if (vty->type == VTY_SHELL_SERV)
2660 for (i = 0; i < vector_active (cmdvec); i++)
2661 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2663 if ((*node->func) (vty))
2664 vty_out (vty, "!%s", VTY_NEWLINE);
2667 else
2669 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2670 VTY_NEWLINE);
2671 vty_out (vty, "!%s", VTY_NEWLINE);
2673 for (i = 0; i < vector_active (cmdvec); i++)
2674 if ((node = vector_slot (cmdvec, i)) && node->func)
2676 if ((*node->func) (vty))
2677 vty_out (vty, "!%s", VTY_NEWLINE);
2679 vty_out (vty, "end%s",VTY_NEWLINE);
2681 return CMD_SUCCESS;
2684 /* Write current configuration into the terminal. */
2685 ALIAS (config_write_terminal,
2686 show_running_config_cmd,
2687 "show running-config",
2688 SHOW_STR
2689 "running configuration\n")
2691 /* Write startup configuration into the terminal. */
2692 DEFUN (show_startup_config,
2693 show_startup_config_cmd,
2694 "show startup-config",
2695 SHOW_STR
2696 "Contentes of startup configuration\n")
2698 char buf[BUFSIZ];
2699 FILE *confp;
2701 confp = fopen (host.config, "r");
2702 if (confp == NULL)
2704 vty_out (vty, "Can't open configuration file [%s]%s",
2705 host.config, VTY_NEWLINE);
2706 return CMD_WARNING;
2709 while (fgets (buf, BUFSIZ, confp))
2711 char *cp = buf;
2713 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2714 cp++;
2715 *cp = '\0';
2717 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2720 fclose (confp);
2722 return CMD_SUCCESS;
2725 /* Hostname configuration */
2726 DEFUN (config_hostname,
2727 hostname_cmd,
2728 "hostname WORD",
2729 "Set system's network name\n"
2730 "This system's network name\n")
2732 if (!isalpha((int) *argv[0]))
2734 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2735 return CMD_WARNING;
2738 if (host.name)
2739 XFREE (MTYPE_HOST, host.name);
2741 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
2742 return CMD_SUCCESS;
2745 DEFUN (config_no_hostname,
2746 no_hostname_cmd,
2747 "no hostname [HOSTNAME]",
2748 NO_STR
2749 "Reset system's network name\n"
2750 "Host name of this router\n")
2752 if (host.name)
2753 XFREE (MTYPE_HOST, host.name);
2754 host.name = NULL;
2755 return CMD_SUCCESS;
2758 /* VTY interface password set. */
2759 DEFUN (config_password, password_cmd,
2760 "password (8|) WORD",
2761 "Assign the terminal connection password\n"
2762 "Specifies a HIDDEN password will follow\n"
2763 "dummy string \n"
2764 "The HIDDEN line password string\n")
2766 /* Argument check. */
2767 if (argc == 0)
2769 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2770 return CMD_WARNING;
2773 if (argc == 2)
2775 if (*argv[0] == '8')
2777 if (host.password)
2778 XFREE (MTYPE_HOST, host.password);
2779 host.password = NULL;
2780 if (host.password_encrypt)
2781 XFREE (MTYPE_HOST, host.password_encrypt);
2782 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2783 return CMD_SUCCESS;
2785 else
2787 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2788 return CMD_WARNING;
2792 if (!isalnum ((int) *argv[0]))
2794 vty_out (vty,
2795 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2796 return CMD_WARNING;
2799 if (host.password)
2800 XFREE (MTYPE_HOST, host.password);
2801 host.password = NULL;
2803 if (host.encrypt)
2805 if (host.password_encrypt)
2806 XFREE (MTYPE_HOST, host.password_encrypt);
2807 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2809 else
2810 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
2812 return CMD_SUCCESS;
2815 ALIAS (config_password, password_text_cmd,
2816 "password LINE",
2817 "Assign the terminal connection password\n"
2818 "The UNENCRYPTED (cleartext) line password\n")
2820 /* VTY enable password set. */
2821 DEFUN (config_enable_password, enable_password_cmd,
2822 "enable password (8|) WORD",
2823 "Modify enable password parameters\n"
2824 "Assign the privileged level password\n"
2825 "Specifies a HIDDEN password will follow\n"
2826 "dummy string \n"
2827 "The HIDDEN 'enable' password string\n")
2829 /* Argument check. */
2830 if (argc == 0)
2832 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2833 return CMD_WARNING;
2836 /* Crypt type is specified. */
2837 if (argc == 2)
2839 if (*argv[0] == '8')
2841 if (host.enable)
2842 XFREE (MTYPE_HOST, host.enable);
2843 host.enable = NULL;
2845 if (host.enable_encrypt)
2846 XFREE (MTYPE_HOST, host.enable_encrypt);
2847 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
2849 return CMD_SUCCESS;
2851 else
2853 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2854 return CMD_WARNING;
2858 if (!isalnum ((int) *argv[0]))
2860 vty_out (vty,
2861 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2862 return CMD_WARNING;
2865 if (host.enable)
2866 XFREE (MTYPE_HOST, host.enable);
2867 host.enable = NULL;
2869 /* Plain password input. */
2870 if (host.encrypt)
2872 if (host.enable_encrypt)
2873 XFREE (MTYPE_HOST, host.enable_encrypt);
2874 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
2876 else
2877 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
2879 return CMD_SUCCESS;
2882 ALIAS (config_enable_password,
2883 enable_password_text_cmd,
2884 "enable password LINE",
2885 "Modify enable password parameters\n"
2886 "Assign the privileged level password\n"
2887 "The UNENCRYPTED (cleartext) 'enable' password\n")
2889 /* VTY enable password delete. */
2890 DEFUN (no_config_enable_password, no_enable_password_cmd,
2891 "no enable password",
2892 NO_STR
2893 "Modify enable password parameters\n"
2894 "Assign the privileged level password\n")
2896 if (host.enable)
2897 XFREE (MTYPE_HOST, host.enable);
2898 host.enable = NULL;
2900 if (host.enable_encrypt)
2901 XFREE (MTYPE_HOST, host.enable_encrypt);
2902 host.enable_encrypt = NULL;
2904 return CMD_SUCCESS;
2907 DEFUN (service_password_encrypt,
2908 service_password_encrypt_cmd,
2909 "service password-encryption",
2910 "Set up miscellaneous service\n"
2911 "Enable encrypted passwords\n")
2913 if (host.encrypt)
2914 return CMD_SUCCESS;
2916 host.encrypt = 1;
2918 if (host.password)
2920 if (host.password_encrypt)
2921 XFREE (MTYPE_HOST, host.password_encrypt);
2922 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
2924 if (host.enable)
2926 if (host.enable_encrypt)
2927 XFREE (MTYPE_HOST, host.enable_encrypt);
2928 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
2931 return CMD_SUCCESS;
2934 DEFUN (no_service_password_encrypt,
2935 no_service_password_encrypt_cmd,
2936 "no service password-encryption",
2937 NO_STR
2938 "Set up miscellaneous service\n"
2939 "Enable encrypted passwords\n")
2941 if (! host.encrypt)
2942 return CMD_SUCCESS;
2944 host.encrypt = 0;
2946 if (host.password_encrypt)
2947 XFREE (MTYPE_HOST, host.password_encrypt);
2948 host.password_encrypt = NULL;
2950 if (host.enable_encrypt)
2951 XFREE (MTYPE_HOST, host.enable_encrypt);
2952 host.enable_encrypt = NULL;
2954 return CMD_SUCCESS;
2957 DEFUN (config_terminal_length, config_terminal_length_cmd,
2958 "terminal length <0-512>",
2959 "Set terminal line parameters\n"
2960 "Set number of lines on a screen\n"
2961 "Number of lines on screen (0 for no pausing)\n")
2963 int lines;
2964 char *endptr = NULL;
2966 lines = strtol (argv[0], &endptr, 10);
2967 if (lines < 0 || lines > 512 || *endptr != '\0')
2969 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2970 return CMD_WARNING;
2972 vty->lines = lines;
2974 return CMD_SUCCESS;
2977 DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2978 "terminal no length",
2979 "Set terminal line parameters\n"
2980 NO_STR
2981 "Set number of lines on a screen\n")
2983 vty->lines = -1;
2984 return CMD_SUCCESS;
2987 DEFUN (service_terminal_length, service_terminal_length_cmd,
2988 "service terminal-length <0-512>",
2989 "Set up miscellaneous service\n"
2990 "System wide terminal length configuration\n"
2991 "Number of lines of VTY (0 means no line control)\n")
2993 int lines;
2994 char *endptr = NULL;
2996 lines = strtol (argv[0], &endptr, 10);
2997 if (lines < 0 || lines > 512 || *endptr != '\0')
2999 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3000 return CMD_WARNING;
3002 host.lines = lines;
3004 return CMD_SUCCESS;
3007 DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3008 "no service terminal-length [<0-512>]",
3009 NO_STR
3010 "Set up miscellaneous service\n"
3011 "System wide terminal length configuration\n"
3012 "Number of lines of VTY (0 means no line control)\n")
3014 host.lines = -1;
3015 return CMD_SUCCESS;
3018 DEFUN_HIDDEN (do_echo,
3019 echo_cmd,
3020 "echo .MESSAGE",
3021 "Echo a message back to the vty\n"
3022 "The message to echo\n")
3024 char *message;
3026 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3027 VTY_NEWLINE);
3028 if (message)
3029 XFREE(MTYPE_TMP, message);
3030 return CMD_SUCCESS;
3033 DEFUN (config_logmsg,
3034 config_logmsg_cmd,
3035 "logmsg "LOG_LEVELS" .MESSAGE",
3036 "Send a message to enabled logging destinations\n"
3037 LOG_LEVEL_DESC
3038 "The message to send\n")
3040 int level;
3041 char *message;
3043 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3044 return CMD_ERR_NO_MATCH;
3046 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3047 if (message)
3048 XFREE(MTYPE_TMP, message);
3049 return CMD_SUCCESS;
3052 DEFUN (show_logging,
3053 show_logging_cmd,
3054 "show logging",
3055 SHOW_STR
3056 "Show current logging configuration\n")
3058 struct zlog *zl = zlog_default;
3060 vty_out (vty, "Syslog logging: ");
3061 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3062 vty_out (vty, "disabled");
3063 else
3064 vty_out (vty, "level %s, facility %s, ident %s",
3065 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3066 facility_name(zl->facility), zl->ident);
3067 vty_out (vty, "%s", VTY_NEWLINE);
3069 vty_out (vty, "Stdout logging: ");
3070 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3071 vty_out (vty, "disabled");
3072 else
3073 vty_out (vty, "level %s",
3074 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3075 vty_out (vty, "%s", VTY_NEWLINE);
3077 vty_out (vty, "Monitor logging: ");
3078 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3079 vty_out (vty, "disabled");
3080 else
3081 vty_out (vty, "level %s",
3082 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3083 vty_out (vty, "%s", VTY_NEWLINE);
3085 vty_out (vty, "File logging: ");
3086 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3087 !zl->fp)
3088 vty_out (vty, "disabled");
3089 else
3090 vty_out (vty, "level %s, filename %s",
3091 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3092 zl->filename);
3093 vty_out (vty, "%s", VTY_NEWLINE);
3095 vty_out (vty, "Protocol name: %s%s",
3096 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3097 vty_out (vty, "Record priority: %s%s",
3098 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3099 vty_out (vty, "Timestamp precision: %d%s",
3100 zl->timestamp_precision, VTY_NEWLINE);
3102 return CMD_SUCCESS;
3105 DEFUN (config_log_stdout,
3106 config_log_stdout_cmd,
3107 "log stdout",
3108 "Logging control\n"
3109 "Set stdout logging level\n")
3111 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3112 return CMD_SUCCESS;
3115 DEFUN (config_log_stdout_level,
3116 config_log_stdout_level_cmd,
3117 "log stdout "LOG_LEVELS,
3118 "Logging control\n"
3119 "Set stdout logging level\n"
3120 LOG_LEVEL_DESC)
3122 int level;
3124 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3125 return CMD_ERR_NO_MATCH;
3126 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
3127 return CMD_SUCCESS;
3130 DEFUN (no_config_log_stdout,
3131 no_config_log_stdout_cmd,
3132 "no log stdout [LEVEL]",
3133 NO_STR
3134 "Logging control\n"
3135 "Cancel logging to stdout\n"
3136 "Logging level\n")
3138 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3139 return CMD_SUCCESS;
3142 DEFUN (config_log_monitor,
3143 config_log_monitor_cmd,
3144 "log monitor",
3145 "Logging control\n"
3146 "Set terminal line (monitor) logging level\n")
3148 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3149 return CMD_SUCCESS;
3152 DEFUN (config_log_monitor_level,
3153 config_log_monitor_level_cmd,
3154 "log monitor "LOG_LEVELS,
3155 "Logging control\n"
3156 "Set terminal line (monitor) logging level\n"
3157 LOG_LEVEL_DESC)
3159 int level;
3161 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3162 return CMD_ERR_NO_MATCH;
3163 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3164 return CMD_SUCCESS;
3167 DEFUN (no_config_log_monitor,
3168 no_config_log_monitor_cmd,
3169 "no log monitor [LEVEL]",
3170 NO_STR
3171 "Logging control\n"
3172 "Disable terminal line (monitor) logging\n"
3173 "Logging level\n")
3175 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3176 return CMD_SUCCESS;
3179 static int
3180 set_log_file(struct vty *vty, const char *fname, int loglevel)
3182 int ret;
3183 char *p = NULL;
3184 const char *fullpath;
3186 /* Path detection. */
3187 if (! IS_DIRECTORY_SEP (*fname))
3189 char cwd[MAXPATHLEN+1];
3190 cwd[MAXPATHLEN] = '\0';
3192 if (getcwd (cwd, MAXPATHLEN) == NULL)
3194 zlog_err ("config_log_file: Unable to alloc mem!");
3195 return CMD_WARNING;
3198 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
3199 == NULL)
3201 zlog_err ("config_log_file: Unable to alloc mem!");
3202 return CMD_WARNING;
3204 sprintf (p, "%s/%s", cwd, fname);
3205 fullpath = p;
3207 else
3208 fullpath = fname;
3210 ret = zlog_set_file (NULL, fullpath, loglevel);
3212 if (p)
3213 XFREE (MTYPE_TMP, p);
3215 if (!ret)
3217 vty_out (vty, "can't open logfile %s\n", fname);
3218 return CMD_WARNING;
3221 if (host.logfile)
3222 XFREE (MTYPE_HOST, host.logfile);
3224 host.logfile = XSTRDUP (MTYPE_HOST, fname);
3226 return CMD_SUCCESS;
3229 DEFUN (config_log_file,
3230 config_log_file_cmd,
3231 "log file FILENAME",
3232 "Logging control\n"
3233 "Logging to file\n"
3234 "Logging filename\n")
3236 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3239 DEFUN (config_log_file_level,
3240 config_log_file_level_cmd,
3241 "log file FILENAME "LOG_LEVELS,
3242 "Logging control\n"
3243 "Logging to file\n"
3244 "Logging filename\n"
3245 LOG_LEVEL_DESC)
3247 int level;
3249 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3250 return CMD_ERR_NO_MATCH;
3251 return set_log_file(vty, argv[0], level);
3254 DEFUN (no_config_log_file,
3255 no_config_log_file_cmd,
3256 "no log file [FILENAME]",
3257 NO_STR
3258 "Logging control\n"
3259 "Cancel logging to file\n"
3260 "Logging file name\n")
3262 zlog_reset_file (NULL);
3264 if (host.logfile)
3265 XFREE (MTYPE_HOST, host.logfile);
3267 host.logfile = NULL;
3269 return CMD_SUCCESS;
3272 ALIAS (no_config_log_file,
3273 no_config_log_file_level_cmd,
3274 "no log file FILENAME LEVEL",
3275 NO_STR
3276 "Logging control\n"
3277 "Cancel logging to file\n"
3278 "Logging file name\n"
3279 "Logging level\n")
3281 DEFUN (config_log_syslog,
3282 config_log_syslog_cmd,
3283 "log syslog",
3284 "Logging control\n"
3285 "Set syslog logging level\n")
3287 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3288 return CMD_SUCCESS;
3291 DEFUN (config_log_syslog_level,
3292 config_log_syslog_level_cmd,
3293 "log syslog "LOG_LEVELS,
3294 "Logging control\n"
3295 "Set syslog logging level\n"
3296 LOG_LEVEL_DESC)
3298 int level;
3300 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3301 return CMD_ERR_NO_MATCH;
3302 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3303 return CMD_SUCCESS;
3306 DEFUN_DEPRECATED (config_log_syslog_facility,
3307 config_log_syslog_facility_cmd,
3308 "log syslog facility "LOG_FACILITIES,
3309 "Logging control\n"
3310 "Logging goes to syslog\n"
3311 "(Deprecated) Facility parameter for syslog messages\n"
3312 LOG_FACILITY_DESC)
3314 int facility;
3316 if ((facility = facility_match(argv[0])) < 0)
3317 return CMD_ERR_NO_MATCH;
3319 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3320 zlog_default->facility = facility;
3321 return CMD_SUCCESS;
3324 DEFUN (no_config_log_syslog,
3325 no_config_log_syslog_cmd,
3326 "no log syslog [LEVEL]",
3327 NO_STR
3328 "Logging control\n"
3329 "Cancel logging to syslog\n"
3330 "Logging level\n")
3332 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3333 return CMD_SUCCESS;
3336 ALIAS (no_config_log_syslog,
3337 no_config_log_syslog_facility_cmd,
3338 "no log syslog facility "LOG_FACILITIES,
3339 NO_STR
3340 "Logging control\n"
3341 "Logging goes to syslog\n"
3342 "Facility parameter for syslog messages\n"
3343 LOG_FACILITY_DESC)
3345 DEFUN (config_log_facility,
3346 config_log_facility_cmd,
3347 "log facility "LOG_FACILITIES,
3348 "Logging control\n"
3349 "Facility parameter for syslog messages\n"
3350 LOG_FACILITY_DESC)
3352 int facility;
3354 if ((facility = facility_match(argv[0])) < 0)
3355 return CMD_ERR_NO_MATCH;
3356 zlog_default->facility = facility;
3357 return CMD_SUCCESS;
3360 DEFUN (no_config_log_facility,
3361 no_config_log_facility_cmd,
3362 "no log facility [FACILITY]",
3363 NO_STR
3364 "Logging control\n"
3365 "Reset syslog facility to default (daemon)\n"
3366 "Syslog facility\n")
3368 zlog_default->facility = LOG_DAEMON;
3369 return CMD_SUCCESS;
3372 DEFUN_DEPRECATED (config_log_trap,
3373 config_log_trap_cmd,
3374 "log trap "LOG_LEVELS,
3375 "Logging control\n"
3376 "(Deprecated) Set logging level and default for all destinations\n"
3377 LOG_LEVEL_DESC)
3379 int new_level ;
3380 int i;
3382 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3383 return CMD_ERR_NO_MATCH;
3385 zlog_default->default_lvl = new_level;
3386 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3387 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3388 zlog_default->maxlvl[i] = new_level;
3389 return CMD_SUCCESS;
3392 DEFUN_DEPRECATED (no_config_log_trap,
3393 no_config_log_trap_cmd,
3394 "no log trap [LEVEL]",
3395 NO_STR
3396 "Logging control\n"
3397 "Permit all logging information\n"
3398 "Logging level\n")
3400 zlog_default->default_lvl = LOG_DEBUG;
3401 return CMD_SUCCESS;
3404 DEFUN (config_log_record_priority,
3405 config_log_record_priority_cmd,
3406 "log record-priority",
3407 "Logging control\n"
3408 "Log the priority of the message within the message\n")
3410 zlog_default->record_priority = 1 ;
3411 return CMD_SUCCESS;
3414 DEFUN (no_config_log_record_priority,
3415 no_config_log_record_priority_cmd,
3416 "no log record-priority",
3417 NO_STR
3418 "Logging control\n"
3419 "Do not log the priority of the message within the message\n")
3421 zlog_default->record_priority = 0 ;
3422 return CMD_SUCCESS;
3425 DEFUN (config_log_timestamp_precision,
3426 config_log_timestamp_precision_cmd,
3427 "log timestamp precision <0-6>",
3428 "Logging control\n"
3429 "Timestamp configuration\n"
3430 "Set the timestamp precision\n"
3431 "Number of subsecond digits\n")
3433 if (argc != 1)
3435 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3436 return CMD_WARNING;
3439 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3440 zlog_default->timestamp_precision, argv[0], 0, 6);
3441 return CMD_SUCCESS;
3444 DEFUN (no_config_log_timestamp_precision,
3445 no_config_log_timestamp_precision_cmd,
3446 "no log timestamp precision",
3447 NO_STR
3448 "Logging control\n"
3449 "Timestamp configuration\n"
3450 "Reset the timestamp precision to the default value of 0\n")
3452 zlog_default->timestamp_precision = 0 ;
3453 return CMD_SUCCESS;
3456 DEFUN (banner_motd_file,
3457 banner_motd_file_cmd,
3458 "banner motd file [FILE]",
3459 "Set banner\n"
3460 "Banner for motd\n"
3461 "Banner from a file\n"
3462 "Filename\n")
3464 if (host.motdfile)
3465 XFREE (MTYPE_HOST, host.motdfile);
3466 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
3468 return CMD_SUCCESS;
3471 DEFUN (banner_motd_default,
3472 banner_motd_default_cmd,
3473 "banner motd default",
3474 "Set banner string\n"
3475 "Strings for motd\n"
3476 "Default string\n")
3478 host.motd = default_motd;
3479 return CMD_SUCCESS;
3482 DEFUN (no_banner_motd,
3483 no_banner_motd_cmd,
3484 "no banner motd",
3485 NO_STR
3486 "Set banner string\n"
3487 "Strings for motd\n")
3489 host.motd = NULL;
3490 if (host.motdfile)
3491 XFREE (MTYPE_HOST, host.motdfile);
3492 host.motdfile = NULL;
3493 return CMD_SUCCESS;
3496 /* Set config filename. Called from vty.c */
3497 void
3498 host_config_set (char *filename)
3500 host.config = XSTRDUP (MTYPE_HOST, filename);
3503 void
3504 install_default (enum node_type node)
3506 install_element (node, &config_exit_cmd);
3507 install_element (node, &config_quit_cmd);
3508 install_element (node, &config_end_cmd);
3509 install_element (node, &config_help_cmd);
3510 install_element (node, &config_list_cmd);
3512 install_element (node, &config_write_terminal_cmd);
3513 install_element (node, &config_write_file_cmd);
3514 install_element (node, &config_write_memory_cmd);
3515 install_element (node, &config_write_cmd);
3516 install_element (node, &show_running_config_cmd);
3519 /* Initialize command interface. Install basic nodes and commands. */
3520 void
3521 cmd_init (int terminal)
3523 /* Allocate initial top vector of commands. */
3524 cmdvec = vector_init (VECTOR_MIN_SIZE);
3526 /* Default host value settings. */
3527 host.name = NULL;
3528 host.password = NULL;
3529 host.enable = NULL;
3530 host.logfile = NULL;
3531 host.config = NULL;
3532 host.lines = -1;
3533 host.motd = default_motd;
3534 host.motdfile = NULL;
3536 /* Install top nodes. */
3537 install_node (&view_node, NULL);
3538 install_node (&enable_node, NULL);
3539 install_node (&auth_node, NULL);
3540 install_node (&auth_enable_node, NULL);
3541 install_node (&config_node, config_write_host);
3543 /* Each node's basic commands. */
3544 install_element (VIEW_NODE, &show_version_cmd);
3545 if (terminal)
3547 install_element (VIEW_NODE, &config_list_cmd);
3548 install_element (VIEW_NODE, &config_exit_cmd);
3549 install_element (VIEW_NODE, &config_quit_cmd);
3550 install_element (VIEW_NODE, &config_help_cmd);
3551 install_element (VIEW_NODE, &config_enable_cmd);
3552 install_element (VIEW_NODE, &config_terminal_length_cmd);
3553 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3554 install_element (VIEW_NODE, &show_logging_cmd);
3555 install_element (VIEW_NODE, &echo_cmd);
3558 if (terminal)
3560 install_default (ENABLE_NODE);
3561 install_element (ENABLE_NODE, &config_disable_cmd);
3562 install_element (ENABLE_NODE, &config_terminal_cmd);
3563 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3565 install_element (ENABLE_NODE, &show_startup_config_cmd);
3566 install_element (ENABLE_NODE, &show_version_cmd);
3568 if (terminal)
3570 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3571 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3572 install_element (ENABLE_NODE, &show_logging_cmd);
3573 install_element (ENABLE_NODE, &echo_cmd);
3574 install_element (ENABLE_NODE, &config_logmsg_cmd);
3576 install_default (CONFIG_NODE);
3579 install_element (CONFIG_NODE, &hostname_cmd);
3580 install_element (CONFIG_NODE, &no_hostname_cmd);
3582 if (terminal)
3584 install_element (CONFIG_NODE, &password_cmd);
3585 install_element (CONFIG_NODE, &password_text_cmd);
3586 install_element (CONFIG_NODE, &enable_password_cmd);
3587 install_element (CONFIG_NODE, &enable_password_text_cmd);
3588 install_element (CONFIG_NODE, &no_enable_password_cmd);
3590 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3591 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
3592 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3593 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3594 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3595 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
3596 install_element (CONFIG_NODE, &config_log_file_cmd);
3597 install_element (CONFIG_NODE, &config_log_file_level_cmd);
3598 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3599 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
3600 install_element (CONFIG_NODE, &config_log_syslog_cmd);
3601 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
3602 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
3603 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
3604 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
3605 install_element (CONFIG_NODE, &config_log_facility_cmd);
3606 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
3607 install_element (CONFIG_NODE, &config_log_trap_cmd);
3608 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3609 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3610 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3611 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3612 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
3613 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3614 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3615 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3616 install_element (CONFIG_NODE, &banner_motd_file_cmd);
3617 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3618 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3619 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
3621 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3622 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
3623 install_element (VIEW_NODE, &show_work_queues_cmd);
3624 install_element (ENABLE_NODE, &show_work_queues_cmd);
3626 srand(time(NULL));