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