File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / command.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 9 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, HEAD
quagga

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>