File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / command.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:54:39 2013 UTC (10 years, 11 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_22p0, v0_99_22, HEAD
0.99.22

    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: " GIT_INFO "\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:   return no_match;
  872: }
  873: 
  874: static enum match_type
  875: cmd_ipv6_prefix_match (const char *str)
  876: {
  877:   int state = STATE_START;
  878:   int colons = 0, nums = 0, double_colon = 0;
  879:   int mask;
  880:   const char *sp = NULL;
  881:   char *endptr = NULL;
  882: 
  883:   if (str == NULL)
  884:     return partly_match;
  885: 
  886:   if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
  887:     return no_match;
  888: 
  889:   while (*str != '\0' && state != STATE_MASK)
  890:     {
  891:       switch (state)
  892: 	{
  893: 	case STATE_START:
  894: 	  if (*str == ':')
  895: 	    {
  896: 	      if (*(str + 1) != ':' && *(str + 1) != '\0')
  897: 		return no_match;
  898: 	      colons--;
  899: 	      state = STATE_COLON;
  900: 	    }
  901: 	  else
  902: 	    {
  903: 	      sp = str;
  904: 	      state = STATE_ADDR;
  905: 	    }
  906: 
  907: 	  continue;
  908: 	case STATE_COLON:
  909: 	  colons++;
  910: 	  if (*(str + 1) == '/')
  911: 	    return no_match;
  912: 	  else if (*(str + 1) == ':')
  913: 	    state = STATE_DOUBLE;
  914: 	  else
  915: 	    {
  916: 	      sp = str + 1;
  917: 	      state = STATE_ADDR;
  918: 	    }
  919: 	  break;
  920: 	case STATE_DOUBLE:
  921: 	  if (double_colon)
  922: 	    return no_match;
  923: 
  924: 	  if (*(str + 1) == ':')
  925: 	    return no_match;
  926: 	  else
  927: 	    {
  928: 	      if (*(str + 1) != '\0' && *(str + 1) != '/')
  929: 		colons++;
  930: 	      sp = str + 1;
  931: 
  932: 	      if (*(str + 1) == '/')
  933: 		state = STATE_SLASH;
  934: 	      else
  935: 		state = STATE_ADDR;
  936: 	    }
  937: 
  938: 	  double_colon++;
  939: 	  nums += 1;
  940: 	  break;
  941: 	case STATE_ADDR:
  942: 	  if (*(str + 1) == ':' || *(str + 1) == '.'
  943: 	      || *(str + 1) == '\0' || *(str + 1) == '/')
  944: 	    {
  945: 	      if (str - sp > 3)
  946: 		return no_match;
  947: 
  948: 	      for (; sp <= str; sp++)
  949: 		if (*sp == '/')
  950: 		  return no_match;
  951: 
  952: 	      nums++;
  953: 
  954: 	      if (*(str + 1) == ':')
  955: 		state = STATE_COLON;
  956: 	      else if (*(str + 1) == '.')
  957: 		{
  958: 		  if (colons || double_colon)
  959: 		    state = STATE_DOT;
  960: 		  else
  961: 		    return no_match;
  962: 		}
  963: 	      else if (*(str + 1) == '/')
  964: 		state = STATE_SLASH;
  965: 	    }
  966: 	  break;
  967: 	case STATE_DOT:
  968: 	  state = STATE_ADDR;
  969: 	  break;
  970: 	case STATE_SLASH:
  971: 	  if (*(str + 1) == '\0')
  972: 	    return partly_match;
  973: 
  974: 	  state = STATE_MASK;
  975: 	  break;
  976: 	default:
  977: 	  break;
  978: 	}
  979: 
  980:       if (nums > 11)
  981: 	return no_match;
  982: 
  983:       if (colons > 7)
  984: 	return no_match;
  985: 
  986:       str++;
  987:     }
  988: 
  989:   if (state < STATE_MASK)
  990:     return partly_match;
  991: 
  992:   mask = strtol (str, &endptr, 10);
  993:   if (*endptr != '\0')
  994:     return no_match;
  995: 
  996:   if (mask < 0 || mask > 128)
  997:     return no_match;
  998:   
  999: /* I don't know why mask < 13 makes command match partly.
 1000:    Forgive me to make this comments. I Want to set static default route
 1001:    because of lack of function to originate default in ospf6d; sorry
 1002:        yasu
 1003:   if (mask < 13)
 1004:     return partly_match;
 1005: */
 1006: 
 1007:   return exact_match;
 1008: }
 1009: 
 1010: #endif /* HAVE_IPV6  */
 1011: 
 1012: #define DECIMAL_STRLEN_MAX 10
 1013: 
 1014: static int
 1015: cmd_range_match (const char *range, const char *str)
 1016: {
 1017:   char *p;
 1018:   char buf[DECIMAL_STRLEN_MAX + 1];
 1019:   char *endptr = NULL;
 1020:   unsigned long min, max, val;
 1021: 
 1022:   if (str == NULL)
 1023:     return 1;
 1024: 
 1025:   val = strtoul (str, &endptr, 10);
 1026:   if (*endptr != '\0')
 1027:     return 0;
 1028: 
 1029:   range++;
 1030:   p = strchr (range, '-');
 1031:   if (p == NULL)
 1032:     return 0;
 1033:   if (p - range > DECIMAL_STRLEN_MAX)
 1034:     return 0;
 1035:   strncpy (buf, range, p - range);
 1036:   buf[p - range] = '\0';
 1037:   min = strtoul (buf, &endptr, 10);
 1038:   if (*endptr != '\0')
 1039:     return 0;
 1040: 
 1041:   range = p + 1;
 1042:   p = strchr (range, '>');
 1043:   if (p == NULL)
 1044:     return 0;
 1045:   if (p - range > DECIMAL_STRLEN_MAX)
 1046:     return 0;
 1047:   strncpy (buf, range, p - range);
 1048:   buf[p - range] = '\0';
 1049:   max = strtoul (buf, &endptr, 10);
 1050:   if (*endptr != '\0')
 1051:     return 0;
 1052: 
 1053:   if (val < min || val > max)
 1054:     return 0;
 1055: 
 1056:   return 1;
 1057: }
 1058: 
 1059: /* Make completion match and return match type flag. */
 1060: static enum match_type
 1061: cmd_filter_by_completion (char *command, vector v, unsigned int index)
 1062: {
 1063:   unsigned int i;
 1064:   const char *str;
 1065:   struct cmd_element *cmd_element;
 1066:   enum match_type match_type;
 1067:   vector descvec;
 1068:   struct desc *desc;
 1069: 
 1070:   match_type = no_match;
 1071: 
 1072:   /* If command and cmd_element string does not match set NULL to vector */
 1073:   for (i = 0; i < vector_active (v); i++)
 1074:     if ((cmd_element = vector_slot (v, i)) != NULL)
 1075:       {
 1076: 	if (index >= vector_active (cmd_element->strvec))
 1077: 	  vector_slot (v, i) = NULL;
 1078: 	else
 1079: 	  {
 1080: 	    unsigned int j;
 1081: 	    int matched = 0;
 1082: 
 1083: 	    descvec = vector_slot (cmd_element->strvec, index);
 1084: 
 1085: 	    for (j = 0; j < vector_active (descvec); j++)
 1086: 	      if ((desc = vector_slot (descvec, j)))
 1087: 		{
 1088: 		  str = desc->cmd;
 1089: 		  
 1090: 		  if (CMD_VARARG (str))
 1091: 		    {
 1092: 		      if (match_type < vararg_match)
 1093: 			match_type = vararg_match;
 1094: 		      matched++;
 1095: 		    }
 1096: 		  else if (CMD_RANGE (str))
 1097: 		    {
 1098: 		      if (cmd_range_match (str, command))
 1099: 			{
 1100: 			  if (match_type < range_match)
 1101: 			    match_type = range_match;
 1102: 
 1103: 			  matched++;
 1104: 			}
 1105: 		    }
 1106: #ifdef HAVE_IPV6
 1107: 		  else if (CMD_IPV6 (str))
 1108: 		    {
 1109: 		      if (cmd_ipv6_match (command))
 1110: 			{
 1111: 			  if (match_type < ipv6_match)
 1112: 			    match_type = ipv6_match;
 1113: 
 1114: 			  matched++;
 1115: 			}
 1116: 		    }
 1117: 		  else if (CMD_IPV6_PREFIX (str))
 1118: 		    {
 1119: 		      if (cmd_ipv6_prefix_match (command))
 1120: 			{
 1121: 			  if (match_type < ipv6_prefix_match)
 1122: 			    match_type = ipv6_prefix_match;
 1123: 
 1124: 			  matched++;
 1125: 			}
 1126: 		    }
 1127: #endif /* HAVE_IPV6  */
 1128: 		  else if (CMD_IPV4 (str))
 1129: 		    {
 1130: 		      if (cmd_ipv4_match (command))
 1131: 			{
 1132: 			  if (match_type < ipv4_match)
 1133: 			    match_type = ipv4_match;
 1134: 
 1135: 			  matched++;
 1136: 			}
 1137: 		    }
 1138: 		  else if (CMD_IPV4_PREFIX (str))
 1139: 		    {
 1140: 		      if (cmd_ipv4_prefix_match (command))
 1141: 			{
 1142: 			  if (match_type < ipv4_prefix_match)
 1143: 			    match_type = ipv4_prefix_match;
 1144: 			  matched++;
 1145: 			}
 1146: 		    }
 1147: 		  else
 1148: 		    /* Check is this point's argument optional ? */
 1149: 		  if (CMD_OPTION (str) || CMD_VARIABLE (str))
 1150: 		    {
 1151: 		      if (match_type < extend_match)
 1152: 			match_type = extend_match;
 1153: 		      matched++;
 1154: 		    }
 1155: 		  else if (strncmp (command, str, strlen (command)) == 0)
 1156: 		    {
 1157: 		      if (strcmp (command, str) == 0)
 1158: 			match_type = exact_match;
 1159: 		      else
 1160: 			{
 1161: 			  if (match_type < partly_match)
 1162: 			    match_type = partly_match;
 1163: 			}
 1164: 		      matched++;
 1165: 		    }
 1166: 		}
 1167: 	    if (!matched)
 1168: 	      vector_slot (v, i) = NULL;
 1169: 	  }
 1170:       }
 1171:   return match_type;
 1172: }
 1173: 
 1174: /* Filter vector by command character with index. */
 1175: static enum match_type
 1176: cmd_filter_by_string (char *command, vector v, unsigned int index)
 1177: {
 1178:   unsigned int i;
 1179:   const char *str;
 1180:   struct cmd_element *cmd_element;
 1181:   enum match_type match_type;
 1182:   vector descvec;
 1183:   struct desc *desc;
 1184: 
 1185:   match_type = no_match;
 1186: 
 1187:   /* If command and cmd_element string does not match set NULL to vector */
 1188:   for (i = 0; i < vector_active (v); i++)
 1189:     if ((cmd_element = vector_slot (v, i)) != NULL)
 1190:       {
 1191: 	/* If given index is bigger than max string vector of command,
 1192: 	   set NULL */
 1193: 	if (index >= vector_active (cmd_element->strvec))
 1194: 	  vector_slot (v, i) = NULL;
 1195: 	else
 1196: 	  {
 1197: 	    unsigned int j;
 1198: 	    int matched = 0;
 1199: 
 1200: 	    descvec = vector_slot (cmd_element->strvec, index);
 1201: 
 1202: 	    for (j = 0; j < vector_active (descvec); j++)
 1203: 	      if ((desc = vector_slot (descvec, j)))
 1204: 		{
 1205: 		  str = desc->cmd;
 1206: 
 1207: 		  if (CMD_VARARG (str))
 1208: 		    {
 1209: 		      if (match_type < vararg_match)
 1210: 			match_type = vararg_match;
 1211: 		      matched++;
 1212: 		    }
 1213: 		  else if (CMD_RANGE (str))
 1214: 		    {
 1215: 		      if (cmd_range_match (str, command))
 1216: 			{
 1217: 			  if (match_type < range_match)
 1218: 			    match_type = range_match;
 1219: 			  matched++;
 1220: 			}
 1221: 		    }
 1222: #ifdef HAVE_IPV6
 1223: 		  else if (CMD_IPV6 (str))
 1224: 		    {
 1225: 		      if (cmd_ipv6_match (command) == exact_match)
 1226: 			{
 1227: 			  if (match_type < ipv6_match)
 1228: 			    match_type = ipv6_match;
 1229: 			  matched++;
 1230: 			}
 1231: 		    }
 1232: 		  else if (CMD_IPV6_PREFIX (str))
 1233: 		    {
 1234: 		      if (cmd_ipv6_prefix_match (command) == exact_match)
 1235: 			{
 1236: 			  if (match_type < ipv6_prefix_match)
 1237: 			    match_type = ipv6_prefix_match;
 1238: 			  matched++;
 1239: 			}
 1240: 		    }
 1241: #endif /* HAVE_IPV6  */
 1242: 		  else if (CMD_IPV4 (str))
 1243: 		    {
 1244: 		      if (cmd_ipv4_match (command) == exact_match)
 1245: 			{
 1246: 			  if (match_type < ipv4_match)
 1247: 			    match_type = ipv4_match;
 1248: 			  matched++;
 1249: 			}
 1250: 		    }
 1251: 		  else if (CMD_IPV4_PREFIX (str))
 1252: 		    {
 1253: 		      if (cmd_ipv4_prefix_match (command) == exact_match)
 1254: 			{
 1255: 			  if (match_type < ipv4_prefix_match)
 1256: 			    match_type = ipv4_prefix_match;
 1257: 			  matched++;
 1258: 			}
 1259: 		    }
 1260: 		  else if (CMD_OPTION (str) || CMD_VARIABLE (str))
 1261: 		    {
 1262: 		      if (match_type < extend_match)
 1263: 			match_type = extend_match;
 1264: 		      matched++;
 1265: 		    }
 1266: 		  else
 1267: 		    {
 1268: 		      if (strcmp (command, str) == 0)
 1269: 			{
 1270: 			  match_type = exact_match;
 1271: 			  matched++;
 1272: 			}
 1273: 		    }
 1274: 		}
 1275: 	    if (!matched)
 1276: 	      vector_slot (v, i) = NULL;
 1277: 	  }
 1278:       }
 1279:   return match_type;
 1280: }
 1281: 
 1282: /* Check ambiguous match */
 1283: static int
 1284: is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
 1285: {
 1286:   unsigned int i;
 1287:   unsigned int j;
 1288:   const char *str = NULL;
 1289:   struct cmd_element *cmd_element;
 1290:   const char *matched = NULL;
 1291:   vector descvec;
 1292:   struct desc *desc;
 1293: 
 1294:   for (i = 0; i < vector_active (v); i++)
 1295:     if ((cmd_element = vector_slot (v, i)) != NULL)
 1296:       {
 1297: 	int match = 0;
 1298: 
 1299: 	descvec = vector_slot (cmd_element->strvec, index);
 1300: 
 1301: 	for (j = 0; j < vector_active (descvec); j++)
 1302: 	  if ((desc = vector_slot (descvec, j)))
 1303: 	    {
 1304: 	      enum match_type ret;
 1305: 	      
 1306: 	      str = desc->cmd;
 1307: 
 1308: 	      switch (type)
 1309: 		{
 1310: 		case exact_match:
 1311: 		  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
 1312: 		      && strcmp (command, str) == 0)
 1313: 		    match++;
 1314: 		  break;
 1315: 		case partly_match:
 1316: 		  if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
 1317: 		      && strncmp (command, str, strlen (command)) == 0)
 1318: 		    {
 1319: 		      if (matched && strcmp (matched, str) != 0)
 1320: 			return 1;	/* There is ambiguous match. */
 1321: 		      else
 1322: 			matched = str;
 1323: 		      match++;
 1324: 		    }
 1325: 		  break;
 1326: 		case range_match:
 1327: 		  if (cmd_range_match (str, command))
 1328: 		    {
 1329: 		      if (matched && strcmp (matched, str) != 0)
 1330: 			return 1;
 1331: 		      else
 1332: 			matched = str;
 1333: 		      match++;
 1334: 		    }
 1335: 		  break;
 1336: #ifdef HAVE_IPV6
 1337: 		case ipv6_match:
 1338: 		  if (CMD_IPV6 (str))
 1339: 		    match++;
 1340: 		  break;
 1341: 		case ipv6_prefix_match:
 1342: 		  if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
 1343: 		    {
 1344: 		      if (ret == partly_match)
 1345: 			return 2;	/* There is incomplete match. */
 1346: 
 1347: 		      match++;
 1348: 		    }
 1349: 		  break;
 1350: #endif /* HAVE_IPV6 */
 1351: 		case ipv4_match:
 1352: 		  if (CMD_IPV4 (str))
 1353: 		    match++;
 1354: 		  break;
 1355: 		case ipv4_prefix_match:
 1356: 		  if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
 1357: 		    {
 1358: 		      if (ret == partly_match)
 1359: 			return 2;	/* There is incomplete match. */
 1360: 
 1361: 		      match++;
 1362: 		    }
 1363: 		  break;
 1364: 		case extend_match:
 1365: 		  if (CMD_OPTION (str) || CMD_VARIABLE (str))
 1366: 		    match++;
 1367: 		  break;
 1368: 		case no_match:
 1369: 		default:
 1370: 		  break;
 1371: 		}
 1372: 	    }
 1373: 	if (!match)
 1374: 	  vector_slot (v, i) = NULL;
 1375:       }
 1376:   return 0;
 1377: }
 1378: 
 1379: /* If src matches dst return dst string, otherwise return NULL */
 1380: static const char *
 1381: cmd_entry_function (const char *src, const char *dst)
 1382: {
 1383:   /* Skip variable arguments. */
 1384:   if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
 1385:       CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
 1386:     return NULL;
 1387: 
 1388:   /* In case of 'command \t', given src is NULL string. */
 1389:   if (src == NULL)
 1390:     return dst;
 1391: 
 1392:   /* Matched with input string. */
 1393:   if (strncmp (src, dst, strlen (src)) == 0)
 1394:     return dst;
 1395: 
 1396:   return NULL;
 1397: }
 1398: 
 1399: /* If src matches dst return dst string, otherwise return NULL */
 1400: /* This version will return the dst string always if it is
 1401:    CMD_VARIABLE for '?' key processing */
 1402: static const char *
 1403: cmd_entry_function_desc (const char *src, const char *dst)
 1404: {
 1405:   if (CMD_VARARG (dst))
 1406:     return dst;
 1407: 
 1408:   if (CMD_RANGE (dst))
 1409:     {
 1410:       if (cmd_range_match (dst, src))
 1411: 	return dst;
 1412:       else
 1413: 	return NULL;
 1414:     }
 1415: 
 1416: #ifdef HAVE_IPV6
 1417:   if (CMD_IPV6 (dst))
 1418:     {
 1419:       if (cmd_ipv6_match (src))
 1420: 	return dst;
 1421:       else
 1422: 	return NULL;
 1423:     }
 1424: 
 1425:   if (CMD_IPV6_PREFIX (dst))
 1426:     {
 1427:       if (cmd_ipv6_prefix_match (src))
 1428: 	return dst;
 1429:       else
 1430: 	return NULL;
 1431:     }
 1432: #endif /* HAVE_IPV6 */
 1433: 
 1434:   if (CMD_IPV4 (dst))
 1435:     {
 1436:       if (cmd_ipv4_match (src))
 1437: 	return dst;
 1438:       else
 1439: 	return NULL;
 1440:     }
 1441: 
 1442:   if (CMD_IPV4_PREFIX (dst))
 1443:     {
 1444:       if (cmd_ipv4_prefix_match (src))
 1445: 	return dst;
 1446:       else
 1447: 	return NULL;
 1448:     }
 1449: 
 1450:   /* Optional or variable commands always match on '?' */
 1451:   if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
 1452:     return dst;
 1453: 
 1454:   /* In case of 'command \t', given src is NULL string. */
 1455:   if (src == NULL)
 1456:     return dst;
 1457: 
 1458:   if (strncmp (src, dst, strlen (src)) == 0)
 1459:     return dst;
 1460:   else
 1461:     return NULL;
 1462: }
 1463: 
 1464: /* Check same string element existence.  If it isn't there return
 1465:     1. */
 1466: static int
 1467: cmd_unique_string (vector v, const char *str)
 1468: {
 1469:   unsigned int i;
 1470:   char *match;
 1471: 
 1472:   for (i = 0; i < vector_active (v); i++)
 1473:     if ((match = vector_slot (v, i)) != NULL)
 1474:       if (strcmp (match, str) == 0)
 1475: 	return 0;
 1476:   return 1;
 1477: }
 1478: 
 1479: /* Compare string to description vector.  If there is same string
 1480:    return 1 else return 0. */
 1481: static int
 1482: desc_unique_string (vector v, const char *str)
 1483: {
 1484:   unsigned int i;
 1485:   struct desc *desc;
 1486: 
 1487:   for (i = 0; i < vector_active (v); i++)
 1488:     if ((desc = vector_slot (v, i)) != NULL)
 1489:       if (strcmp (desc->cmd, str) == 0)
 1490: 	return 1;
 1491:   return 0;
 1492: }
 1493: 
 1494: static int 
 1495: cmd_try_do_shortcut (enum node_type node, char* first_word) {
 1496:   if ( first_word != NULL &&
 1497:        node != AUTH_NODE &&
 1498:        node != VIEW_NODE &&
 1499:        node != AUTH_ENABLE_NODE &&
 1500:        node != ENABLE_NODE &&
 1501:        node != RESTRICTED_NODE &&
 1502:        0 == strcmp( "do", first_word ) )
 1503:     return 1;
 1504:   return 0;
 1505: }
 1506: 
 1507: /* '?' describe command support. */
 1508: static vector
 1509: cmd_describe_command_real (vector vline, struct vty *vty, int *status)
 1510: {
 1511:   unsigned int i;
 1512:   vector cmd_vector;
 1513: #define INIT_MATCHVEC_SIZE 10
 1514:   vector matchvec;
 1515:   struct cmd_element *cmd_element;
 1516:   unsigned int index;
 1517:   int ret;
 1518:   enum match_type match;
 1519:   char *command;
 1520: 
 1521:   /* Set index. */
 1522:   if (vector_active (vline) == 0)
 1523:     {
 1524:       *status = CMD_ERR_NO_MATCH;
 1525:       return NULL;
 1526:     }
 1527:   else
 1528:     index = vector_active (vline) - 1;
 1529:   
 1530:   /* Make copy vector of current node's command vector. */
 1531:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
 1532: 
 1533:   /* Prepare match vector */
 1534:   matchvec = vector_init (INIT_MATCHVEC_SIZE);
 1535: 
 1536:   /* Filter commands. */
 1537:   /* Only words precedes current word will be checked in this loop. */
 1538:   for (i = 0; i < index; i++)
 1539:     if ((command = vector_slot (vline, i)))
 1540:       {
 1541: 	match = cmd_filter_by_completion (command, cmd_vector, i);
 1542: 	
 1543: 	if (match == vararg_match)
 1544: 	  {
 1545: 	    struct cmd_element *cmd_element;
 1546: 	    vector descvec;
 1547: 	    unsigned int j, k;
 1548: 
 1549: 	    for (j = 0; j < vector_active (cmd_vector); j++)
 1550: 	      if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
 1551: 		  && (vector_active (cmd_element->strvec)))
 1552: 		{
 1553: 		  descvec = vector_slot (cmd_element->strvec,
 1554: 					 vector_active (cmd_element->strvec) - 1);
 1555: 		  for (k = 0; k < vector_active (descvec); k++)
 1556: 		    {
 1557: 		      struct desc *desc = vector_slot (descvec, k);
 1558: 		      vector_set (matchvec, desc);
 1559: 		    }
 1560: 		}
 1561:             
 1562: 	    vector_set (matchvec, &desc_cr);
 1563: 	    vector_free (cmd_vector);
 1564: 
 1565: 	    return matchvec;
 1566: 	  }
 1567: 
 1568: 	if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
 1569: 	  {
 1570: 	    vector_free (cmd_vector);
 1571: 	    vector_free (matchvec);
 1572: 	    *status = CMD_ERR_AMBIGUOUS;
 1573: 	    return NULL;
 1574: 	  }
 1575: 	else if (ret == 2)
 1576: 	  {
 1577: 	    vector_free (cmd_vector);
 1578: 	    vector_free (matchvec);
 1579: 	    *status = CMD_ERR_NO_MATCH;
 1580: 	    return NULL;
 1581: 	  }
 1582:       }
 1583: 
 1584:   /* Prepare match vector */
 1585:   /*  matchvec = vector_init (INIT_MATCHVEC_SIZE); */
 1586: 
 1587:   /* Make sure that cmd_vector is filtered based on current word */
 1588:   command = vector_slot (vline, index);
 1589:   if (command)
 1590:     match = cmd_filter_by_completion (command, cmd_vector, index);
 1591: 
 1592:   /* Make description vector. */
 1593:   for (i = 0; i < vector_active (cmd_vector); i++)
 1594:     if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
 1595:       {
 1596: 	vector strvec = cmd_element->strvec;
 1597: 
 1598: 	/* if command is NULL, index may be equal to vector_active */
 1599: 	if (command && index >= vector_active (strvec))
 1600: 	  vector_slot (cmd_vector, i) = NULL;
 1601: 	else
 1602: 	  {
 1603: 	    /* Check if command is completed. */
 1604: 	    if (command == NULL && index == vector_active (strvec))
 1605: 	      {
 1606: 		if (!desc_unique_string (matchvec, command_cr))
 1607: 		  vector_set (matchvec, &desc_cr);
 1608: 	      }
 1609: 	    else
 1610: 	      {
 1611: 		unsigned int j;
 1612: 		vector descvec = vector_slot (strvec, index);
 1613: 		struct desc *desc;
 1614: 
 1615: 		for (j = 0; j < vector_active (descvec); j++)
 1616: 		  if ((desc = vector_slot (descvec, j)))
 1617: 		    {
 1618: 		      const char *string;
 1619: 
 1620: 		      string = cmd_entry_function_desc (command, desc->cmd);
 1621: 		      if (string)
 1622: 			{
 1623: 			  /* Uniqueness check */
 1624: 			  if (!desc_unique_string (matchvec, string))
 1625: 			    vector_set (matchvec, desc);
 1626: 			}
 1627: 		    }
 1628: 	      }
 1629: 	  }
 1630:       }
 1631:   vector_free (cmd_vector);
 1632: 
 1633:   if (vector_slot (matchvec, 0) == NULL)
 1634:     {
 1635:       vector_free (matchvec);
 1636:       *status = CMD_ERR_NO_MATCH;
 1637:       return NULL;
 1638:     }
 1639: 
 1640:   *status = CMD_SUCCESS;
 1641:   return matchvec;
 1642: }
 1643: 
 1644: vector
 1645: cmd_describe_command (vector vline, struct vty *vty, int *status)
 1646: {
 1647:   vector ret;
 1648: 
 1649:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
 1650:     {
 1651:       enum node_type onode;
 1652:       vector shifted_vline;
 1653:       unsigned int index;
 1654: 
 1655:       onode = vty->node;
 1656:       vty->node = ENABLE_NODE;
 1657:       /* We can try it on enable node, cos' the vty is authenticated */
 1658: 
 1659:       shifted_vline = vector_init (vector_count(vline));
 1660:       /* use memcpy? */
 1661:       for (index = 1; index < vector_active (vline); index++) 
 1662: 	{
 1663: 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
 1664: 	}
 1665: 
 1666:       ret = cmd_describe_command_real (shifted_vline, vty, status);
 1667: 
 1668:       vector_free(shifted_vline);
 1669:       vty->node = onode;
 1670:       return ret;
 1671:   }
 1672: 
 1673: 
 1674:   return cmd_describe_command_real (vline, vty, status);
 1675: }
 1676: 
 1677: 
 1678: /* Check LCD of matched command. */
 1679: static int
 1680: cmd_lcd (char **matched)
 1681: {
 1682:   int i;
 1683:   int j;
 1684:   int lcd = -1;
 1685:   char *s1, *s2;
 1686:   char c1, c2;
 1687: 
 1688:   if (matched[0] == NULL || matched[1] == NULL)
 1689:     return 0;
 1690: 
 1691:   for (i = 1; matched[i] != NULL; i++)
 1692:     {
 1693:       s1 = matched[i - 1];
 1694:       s2 = matched[i];
 1695: 
 1696:       for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
 1697: 	if (c1 != c2)
 1698: 	  break;
 1699: 
 1700:       if (lcd < 0)
 1701: 	lcd = j;
 1702:       else
 1703: 	{
 1704: 	  if (lcd > j)
 1705: 	    lcd = j;
 1706: 	}
 1707:     }
 1708:   return lcd;
 1709: }
 1710: 
 1711: /* Command line completion support. */
 1712: static char **
 1713: cmd_complete_command_real (vector vline, struct vty *vty, int *status)
 1714: {
 1715:   unsigned int i;
 1716:   vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
 1717: #define INIT_MATCHVEC_SIZE 10
 1718:   vector matchvec;
 1719:   struct cmd_element *cmd_element;
 1720:   unsigned int index;
 1721:   char **match_str;
 1722:   struct desc *desc;
 1723:   vector descvec;
 1724:   char *command;
 1725:   int lcd;
 1726: 
 1727:   if (vector_active (vline) == 0)
 1728:     {
 1729:       vector_free (cmd_vector);
 1730:       *status = CMD_ERR_NO_MATCH;
 1731:       return NULL;
 1732:     }
 1733:   else
 1734:     index = vector_active (vline) - 1;
 1735: 
 1736:   /* First, filter by preceeding command string */
 1737:   for (i = 0; i < index; i++)
 1738:     if ((command = vector_slot (vline, i)))
 1739:       {
 1740: 	enum match_type match;
 1741: 	int ret;
 1742: 
 1743: 	/* First try completion match, if there is exactly match return 1 */
 1744: 	match = cmd_filter_by_completion (command, cmd_vector, i);
 1745: 
 1746: 	/* If there is exact match then filter ambiguous match else check
 1747: 	   ambiguousness. */
 1748: 	if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
 1749: 	  {
 1750: 	    vector_free (cmd_vector);
 1751: 	    *status = CMD_ERR_AMBIGUOUS;
 1752: 	    return NULL;
 1753: 	  }
 1754: 	/*
 1755: 	   else if (ret == 2)
 1756: 	   {
 1757: 	   vector_free (cmd_vector);
 1758: 	   *status = CMD_ERR_NO_MATCH;
 1759: 	   return NULL;
 1760: 	   }
 1761: 	 */
 1762:       }
 1763:   
 1764:   /* Prepare match vector. */
 1765:   matchvec = vector_init (INIT_MATCHVEC_SIZE);
 1766: 
 1767:   /* Now we got into completion */
 1768:   for (i = 0; i < vector_active (cmd_vector); i++)
 1769:     if ((cmd_element = vector_slot (cmd_vector, i)))
 1770:       {
 1771: 	const char *string;
 1772: 	vector strvec = cmd_element->strvec;
 1773: 
 1774: 	/* Check field length */
 1775: 	if (index >= vector_active (strvec))
 1776: 	  vector_slot (cmd_vector, i) = NULL;
 1777: 	else
 1778: 	  {
 1779: 	    unsigned int j;
 1780: 
 1781: 	    descvec = vector_slot (strvec, index);
 1782: 	    for (j = 0; j < vector_active (descvec); j++)
 1783: 	      if ((desc = vector_slot (descvec, j)))
 1784: 		{
 1785: 		  if ((string = 
 1786: 		       cmd_entry_function (vector_slot (vline, index),
 1787: 					   desc->cmd)))
 1788: 		    if (cmd_unique_string (matchvec, string))
 1789: 		      vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
 1790: 		}
 1791: 	  }
 1792:       }
 1793: 
 1794:   /* We don't need cmd_vector any more. */
 1795:   vector_free (cmd_vector);
 1796: 
 1797:   /* No matched command */
 1798:   if (vector_slot (matchvec, 0) == NULL)
 1799:     {
 1800:       vector_free (matchvec);
 1801: 
 1802:       /* In case of 'command \t' pattern.  Do you need '?' command at
 1803:          the end of the line. */
 1804:       if (vector_slot (vline, index) == '\0')
 1805: 	*status = CMD_ERR_NOTHING_TODO;
 1806:       else
 1807: 	*status = CMD_ERR_NO_MATCH;
 1808:       return NULL;
 1809:     }
 1810: 
 1811:   /* Only one matched */
 1812:   if (vector_slot (matchvec, 1) == NULL)
 1813:     {
 1814:       match_str = (char **) matchvec->index;
 1815:       vector_only_wrapper_free (matchvec);
 1816:       *status = CMD_COMPLETE_FULL_MATCH;
 1817:       return match_str;
 1818:     }
 1819:   /* Make it sure last element is NULL. */
 1820:   vector_set (matchvec, NULL);
 1821: 
 1822:   /* Check LCD of matched strings. */
 1823:   if (vector_slot (vline, index) != NULL)
 1824:     {
 1825:       lcd = cmd_lcd ((char **) matchvec->index);
 1826: 
 1827:       if (lcd)
 1828: 	{
 1829: 	  int len = strlen (vector_slot (vline, index));
 1830: 
 1831: 	  if (len < lcd)
 1832: 	    {
 1833: 	      char *lcdstr;
 1834: 
 1835: 	      lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
 1836: 	      memcpy (lcdstr, matchvec->index[0], lcd);
 1837: 	      lcdstr[lcd] = '\0';
 1838: 
 1839: 	      /* match_str = (char **) &lcdstr; */
 1840: 
 1841: 	      /* Free matchvec. */
 1842: 	      for (i = 0; i < vector_active (matchvec); i++)
 1843: 		{
 1844: 		  if (vector_slot (matchvec, i))
 1845: 		    XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
 1846: 		}
 1847: 	      vector_free (matchvec);
 1848: 
 1849: 	      /* Make new matchvec. */
 1850: 	      matchvec = vector_init (INIT_MATCHVEC_SIZE);
 1851: 	      vector_set (matchvec, lcdstr);
 1852: 	      match_str = (char **) matchvec->index;
 1853: 	      vector_only_wrapper_free (matchvec);
 1854: 
 1855: 	      *status = CMD_COMPLETE_MATCH;
 1856: 	      return match_str;
 1857: 	    }
 1858: 	}
 1859:     }
 1860: 
 1861:   match_str = (char **) matchvec->index;
 1862:   vector_only_wrapper_free (matchvec);
 1863:   *status = CMD_COMPLETE_LIST_MATCH;
 1864:   return match_str;
 1865: }
 1866: 
 1867: char **
 1868: cmd_complete_command (vector vline, struct vty *vty, int *status)
 1869: {
 1870:   char **ret;
 1871: 
 1872:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
 1873:     {
 1874:       enum node_type onode;
 1875:       vector shifted_vline;
 1876:       unsigned int index;
 1877: 
 1878:       onode = vty->node;
 1879:       vty->node = ENABLE_NODE;
 1880:       /* We can try it on enable node, cos' the vty is authenticated */
 1881: 
 1882:       shifted_vline = vector_init (vector_count(vline));
 1883:       /* use memcpy? */
 1884:       for (index = 1; index < vector_active (vline); index++) 
 1885: 	{
 1886: 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
 1887: 	}
 1888: 
 1889:       ret = cmd_complete_command_real (shifted_vline, vty, status);
 1890: 
 1891:       vector_free(shifted_vline);
 1892:       vty->node = onode;
 1893:       return ret;
 1894:   }
 1895: 
 1896: 
 1897:   return cmd_complete_command_real (vline, vty, status);
 1898: }
 1899: 
 1900: /* return parent node */
 1901: /* MUST eventually converge on CONFIG_NODE */
 1902: enum node_type
 1903: node_parent ( enum node_type node )
 1904: {
 1905:   enum node_type ret;
 1906: 
 1907:   assert (node > CONFIG_NODE);
 1908: 
 1909:   switch (node)
 1910:     {
 1911:     case BGP_VPNV4_NODE:
 1912:     case BGP_IPV4_NODE:
 1913:     case BGP_IPV4M_NODE:
 1914:     case BGP_IPV6_NODE:
 1915:     case BGP_IPV6M_NODE:
 1916:       ret = BGP_NODE;
 1917:       break;
 1918:     case KEYCHAIN_KEY_NODE:
 1919:       ret = KEYCHAIN_NODE;
 1920:       break;
 1921:     default:
 1922:       ret = CONFIG_NODE;
 1923:     }
 1924: 
 1925:   return ret;
 1926: }
 1927: 
 1928: /* Execute command by argument vline vector. */
 1929: static int
 1930: cmd_execute_command_real (vector vline, struct vty *vty,
 1931: 			  struct cmd_element **cmd)
 1932: {
 1933:   unsigned int i;
 1934:   unsigned int index;
 1935:   vector cmd_vector;
 1936:   struct cmd_element *cmd_element;
 1937:   struct cmd_element *matched_element;
 1938:   unsigned int matched_count, incomplete_count;
 1939:   int argc;
 1940:   const char *argv[CMD_ARGC_MAX];
 1941:   enum match_type match = 0;
 1942:   int varflag;
 1943:   char *command;
 1944: 
 1945:   /* Make copy of command elements. */
 1946:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
 1947: 
 1948:   for (index = 0; index < vector_active (vline); index++)
 1949:     if ((command = vector_slot (vline, index)))
 1950:       {
 1951: 	int ret;
 1952: 
 1953: 	match = cmd_filter_by_completion (command, cmd_vector, index);
 1954: 
 1955: 	if (match == vararg_match)
 1956: 	  break;
 1957:         
 1958: 	ret = is_cmd_ambiguous (command, cmd_vector, index, match);
 1959: 
 1960: 	if (ret == 1)
 1961: 	  {
 1962: 	    vector_free (cmd_vector);
 1963: 	    return CMD_ERR_AMBIGUOUS;
 1964: 	  }
 1965: 	else if (ret == 2)
 1966: 	  {
 1967: 	    vector_free (cmd_vector);
 1968: 	    return CMD_ERR_NO_MATCH;
 1969: 	  }
 1970:       }
 1971: 
 1972:   /* Check matched count. */
 1973:   matched_element = NULL;
 1974:   matched_count = 0;
 1975:   incomplete_count = 0;
 1976: 
 1977:   for (i = 0; i < vector_active (cmd_vector); i++)
 1978:     if ((cmd_element = vector_slot (cmd_vector, i)))
 1979:       {
 1980: 	if (match == vararg_match || index >= cmd_element->cmdsize)
 1981: 	  {
 1982: 	    matched_element = cmd_element;
 1983: #if 0
 1984: 	    printf ("DEBUG: %s\n", cmd_element->string);
 1985: #endif
 1986: 	    matched_count++;
 1987: 	  }
 1988: 	else
 1989: 	  {
 1990: 	    incomplete_count++;
 1991: 	  }
 1992:       }
 1993: 
 1994:   /* Finish of using cmd_vector. */
 1995:   vector_free (cmd_vector);
 1996: 
 1997:   /* To execute command, matched_count must be 1. */
 1998:   if (matched_count == 0)
 1999:     {
 2000:       if (incomplete_count)
 2001: 	return CMD_ERR_INCOMPLETE;
 2002:       else
 2003: 	return CMD_ERR_NO_MATCH;
 2004:     }
 2005: 
 2006:   if (matched_count > 1)
 2007:     return CMD_ERR_AMBIGUOUS;
 2008: 
 2009:   /* Argument treatment */
 2010:   varflag = 0;
 2011:   argc = 0;
 2012: 
 2013:   for (i = 0; i < vector_active (vline); i++)
 2014:     {
 2015:       if (varflag)
 2016: 	argv[argc++] = vector_slot (vline, i);
 2017:       else
 2018: 	{
 2019: 	  vector descvec = vector_slot (matched_element->strvec, i);
 2020: 
 2021: 	  if (vector_active (descvec) == 1)
 2022: 	    {
 2023: 	      struct desc *desc = vector_slot (descvec, 0);
 2024: 
 2025: 	      if (CMD_VARARG (desc->cmd))
 2026: 		varflag = 1;
 2027: 
 2028: 	      if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
 2029: 		argv[argc++] = vector_slot (vline, i);
 2030: 	    }
 2031: 	  else
 2032: 	    argv[argc++] = vector_slot (vline, i);
 2033: 	}
 2034: 
 2035:       if (argc >= CMD_ARGC_MAX)
 2036: 	return CMD_ERR_EXEED_ARGC_MAX;
 2037:     }
 2038: 
 2039:   /* For vtysh execution. */
 2040:   if (cmd)
 2041:     *cmd = matched_element;
 2042: 
 2043:   if (matched_element->daemon)
 2044:     return CMD_SUCCESS_DAEMON;
 2045: 
 2046:   /* Execute matched command. */
 2047:   return (*matched_element->func) (matched_element, vty, argc, argv);
 2048: }
 2049: 
 2050: int
 2051: cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
 2052: 		     int vtysh) {
 2053:   int ret, saved_ret, tried = 0;
 2054:   enum node_type onode, try_node;
 2055: 
 2056:   onode = try_node = vty->node;
 2057: 
 2058:   if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
 2059:     {
 2060:       vector shifted_vline;
 2061:       unsigned int index;
 2062: 
 2063:       vty->node = ENABLE_NODE;
 2064:       /* We can try it on enable node, cos' the vty is authenticated */
 2065: 
 2066:       shifted_vline = vector_init (vector_count(vline));
 2067:       /* use memcpy? */
 2068:       for (index = 1; index < vector_active (vline); index++) 
 2069: 	{
 2070: 	  vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
 2071: 	}
 2072: 
 2073:       ret = cmd_execute_command_real (shifted_vline, vty, cmd);
 2074: 
 2075:       vector_free(shifted_vline);
 2076:       vty->node = onode;
 2077:       return ret;
 2078:   }
 2079: 
 2080: 
 2081:   saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
 2082: 
 2083:   if (vtysh)
 2084:     return saved_ret;
 2085: 
 2086:   /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
 2087:   while ( ret != CMD_SUCCESS && ret != CMD_WARNING 
 2088: 	  && vty->node > CONFIG_NODE )
 2089:     {
 2090:       try_node = node_parent(try_node);
 2091:       vty->node = try_node;
 2092:       ret = cmd_execute_command_real (vline, vty, cmd);
 2093:       tried = 1;
 2094:       if (ret == CMD_SUCCESS || ret == CMD_WARNING)
 2095: 	{
 2096: 	  /* succesfull command, leave the node as is */
 2097: 	  return ret;
 2098: 	}
 2099:     }
 2100:   /* no command succeeded, reset the vty to the original node and
 2101:      return the error for this node */
 2102:   if ( tried )
 2103:     vty->node = onode;
 2104:   return saved_ret;
 2105: }
 2106: 
 2107: /* Execute command by argument readline. */
 2108: int
 2109: cmd_execute_command_strict (vector vline, struct vty *vty,
 2110: 			    struct cmd_element **cmd)
 2111: {
 2112:   unsigned int i;
 2113:   unsigned int index;
 2114:   vector cmd_vector;
 2115:   struct cmd_element *cmd_element;
 2116:   struct cmd_element *matched_element;
 2117:   unsigned int matched_count, incomplete_count;
 2118:   int argc;
 2119:   const char *argv[CMD_ARGC_MAX];
 2120:   int varflag;
 2121:   enum match_type match = 0;
 2122:   char *command;
 2123: 
 2124:   /* Make copy of command element */
 2125:   cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
 2126: 
 2127:   for (index = 0; index < vector_active (vline); index++)
 2128:     if ((command = vector_slot (vline, index)))
 2129:       {
 2130: 	int ret;
 2131: 	
 2132: 	match = cmd_filter_by_string (vector_slot (vline, index),
 2133: 				      cmd_vector, index);
 2134: 
 2135: 	/* If command meets '.VARARG' then finish matching. */
 2136: 	if (match == vararg_match)
 2137: 	  break;
 2138:         
 2139: 	ret = is_cmd_ambiguous (command, cmd_vector, index, match);
 2140: 	if (ret == 1)
 2141: 	  {
 2142: 	    vector_free (cmd_vector);
 2143: 	    return CMD_ERR_AMBIGUOUS;
 2144: 	  }
 2145: 	if (ret == 2)
 2146: 	  {
 2147: 	    vector_free (cmd_vector);
 2148: 	    return CMD_ERR_NO_MATCH;
 2149: 	  }
 2150:       }
 2151: 
 2152:   /* Check matched count. */
 2153:   matched_element = NULL;
 2154:   matched_count = 0;
 2155:   incomplete_count = 0;
 2156:   for (i = 0; i < vector_active (cmd_vector); i++)
 2157:     if (vector_slot (cmd_vector, i) != NULL)
 2158:       {
 2159: 	cmd_element = vector_slot (cmd_vector, i);
 2160: 
 2161: 	if (match == vararg_match || index >= cmd_element->cmdsize)
 2162: 	  {
 2163: 	    matched_element = cmd_element;
 2164: 	    matched_count++;
 2165: 	  }
 2166: 	else
 2167: 	  incomplete_count++;
 2168:       }
 2169: 
 2170:   /* Finish of using cmd_vector. */
 2171:   vector_free (cmd_vector);
 2172: 
 2173:   /* To execute command, matched_count must be 1. */
 2174:   if (matched_count == 0)
 2175:     {
 2176:       if (incomplete_count)
 2177: 	return CMD_ERR_INCOMPLETE;
 2178:       else
 2179: 	return CMD_ERR_NO_MATCH;
 2180:     }
 2181: 
 2182:   if (matched_count > 1)
 2183:     return CMD_ERR_AMBIGUOUS;
 2184: 
 2185:   /* Argument treatment */
 2186:   varflag = 0;
 2187:   argc = 0;
 2188: 
 2189:   for (i = 0; i < vector_active (vline); i++)
 2190:     {
 2191:       if (varflag)
 2192: 	argv[argc++] = vector_slot (vline, i);
 2193:       else
 2194: 	{
 2195: 	  vector descvec = vector_slot (matched_element->strvec, i);
 2196: 
 2197: 	  if (vector_active (descvec) == 1)
 2198: 	    {
 2199: 	      struct desc *desc = vector_slot (descvec, 0);
 2200: 
 2201: 	      if (CMD_VARARG (desc->cmd))
 2202: 		varflag = 1;
 2203: 
 2204: 	      if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
 2205: 		argv[argc++] = vector_slot (vline, i);
 2206: 	    }
 2207: 	  else
 2208: 	    argv[argc++] = vector_slot (vline, i);
 2209: 	}
 2210: 
 2211:       if (argc >= CMD_ARGC_MAX)
 2212: 	return CMD_ERR_EXEED_ARGC_MAX;
 2213:     }
 2214: 
 2215:   /* For vtysh execution. */
 2216:   if (cmd)
 2217:     *cmd = matched_element;
 2218: 
 2219:   if (matched_element->daemon)
 2220:     return CMD_SUCCESS_DAEMON;
 2221: 
 2222:   /* Now execute matched command */
 2223:   return (*matched_element->func) (matched_element, vty, argc, argv);
 2224: }
 2225: 
 2226: /* Configration make from file. */
 2227: int
 2228: config_from_file (struct vty *vty, FILE *fp)
 2229: {
 2230:   int ret;
 2231:   vector vline;
 2232: 
 2233:   while (fgets (vty->buf, VTY_BUFSIZ, fp))
 2234:     {
 2235:       vline = cmd_make_strvec (vty->buf);
 2236: 
 2237:       /* In case of comment line */
 2238:       if (vline == NULL)
 2239: 	continue;
 2240:       /* Execute configuration command : this is strict match */
 2241:       ret = cmd_execute_command_strict (vline, vty, NULL);
 2242: 
 2243:       /* Try again with setting node to CONFIG_NODE */
 2244:       while (ret != CMD_SUCCESS && ret != CMD_WARNING
 2245: 	     && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
 2246: 	{
 2247: 	  vty->node = node_parent(vty->node);
 2248: 	  ret = cmd_execute_command_strict (vline, vty, NULL);
 2249: 	}
 2250: 
 2251:       cmd_free_strvec (vline);
 2252: 
 2253:       if (ret != CMD_SUCCESS && ret != CMD_WARNING
 2254: 	  && ret != CMD_ERR_NOTHING_TODO)
 2255: 	return ret;
 2256:     }
 2257:   return CMD_SUCCESS;
 2258: }
 2259: 
 2260: /* Configration from terminal */
 2261: DEFUN (config_terminal,
 2262:        config_terminal_cmd,
 2263:        "configure terminal",
 2264:        "Configuration from vty interface\n"
 2265:        "Configuration terminal\n")
 2266: {
 2267:   if (vty_config_lock (vty))
 2268:     vty->node = CONFIG_NODE;
 2269:   else
 2270:     {
 2271:       vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
 2272:       return CMD_WARNING;
 2273:     }
 2274:   return CMD_SUCCESS;
 2275: }
 2276: 
 2277: /* Enable command */
 2278: DEFUN (enable, 
 2279:        config_enable_cmd,
 2280:        "enable",
 2281:        "Turn on privileged mode command\n")
 2282: {
 2283:   /* If enable password is NULL, change to ENABLE_NODE */
 2284:   if ((host.enable == NULL && host.enable_encrypt == NULL) ||
 2285:       vty->type == VTY_SHELL_SERV)
 2286:     vty->node = ENABLE_NODE;
 2287:   else
 2288:     vty->node = AUTH_ENABLE_NODE;
 2289: 
 2290:   return CMD_SUCCESS;
 2291: }
 2292: 
 2293: /* Disable command */
 2294: DEFUN (disable, 
 2295:        config_disable_cmd,
 2296:        "disable",
 2297:        "Turn off privileged mode command\n")
 2298: {
 2299:   if (vty->node == ENABLE_NODE)
 2300:     vty->node = VIEW_NODE;
 2301:   return CMD_SUCCESS;
 2302: }
 2303: 
 2304: /* Down vty node level. */
 2305: DEFUN (config_exit,
 2306:        config_exit_cmd,
 2307:        "exit",
 2308:        "Exit current mode and down to previous mode\n")
 2309: {
 2310:   switch (vty->node)
 2311:     {
 2312:     case VIEW_NODE:
 2313:     case ENABLE_NODE:
 2314:     case RESTRICTED_NODE:
 2315:       if (vty_shell (vty))
 2316: 	exit (0);
 2317:       else
 2318: 	vty->status = VTY_CLOSE;
 2319:       break;
 2320:     case CONFIG_NODE:
 2321:       vty->node = ENABLE_NODE;
 2322:       vty_config_unlock (vty);
 2323:       break;
 2324:     case INTERFACE_NODE:
 2325:     case ZEBRA_NODE:
 2326:     case BGP_NODE:
 2327:     case RIP_NODE:
 2328:     case RIPNG_NODE:
 2329:     case BABEL_NODE:
 2330:     case OSPF_NODE:
 2331:     case OSPF6_NODE:
 2332:     case ISIS_NODE:
 2333:     case KEYCHAIN_NODE:
 2334:     case MASC_NODE:
 2335:     case RMAP_NODE:
 2336:     case VTY_NODE:
 2337:       vty->node = CONFIG_NODE;
 2338:       break;
 2339:     case BGP_VPNV4_NODE:
 2340:     case BGP_IPV4_NODE:
 2341:     case BGP_IPV4M_NODE:
 2342:     case BGP_IPV6_NODE:
 2343:     case BGP_IPV6M_NODE:
 2344:       vty->node = BGP_NODE;
 2345:       break;
 2346:     case KEYCHAIN_KEY_NODE:
 2347:       vty->node = KEYCHAIN_NODE;
 2348:       break;
 2349:     default:
 2350:       break;
 2351:     }
 2352:   return CMD_SUCCESS;
 2353: }
 2354: 
 2355: /* quit is alias of exit. */
 2356: ALIAS (config_exit,
 2357:        config_quit_cmd,
 2358:        "quit",
 2359:        "Exit current mode and down to previous mode\n")
 2360:        
 2361: /* End of configuration. */
 2362: DEFUN (config_end,
 2363:        config_end_cmd,
 2364:        "end",
 2365:        "End current mode and change to enable mode.")
 2366: {
 2367:   switch (vty->node)
 2368:     {
 2369:     case VIEW_NODE:
 2370:     case ENABLE_NODE:
 2371:     case RESTRICTED_NODE:
 2372:       /* Nothing to do. */
 2373:       break;
 2374:     case CONFIG_NODE:
 2375:     case INTERFACE_NODE:
 2376:     case ZEBRA_NODE:
 2377:     case RIP_NODE:
 2378:     case RIPNG_NODE:
 2379:     case BABEL_NODE:
 2380:     case BGP_NODE:
 2381:     case BGP_VPNV4_NODE:
 2382:     case BGP_IPV4_NODE:
 2383:     case BGP_IPV4M_NODE:
 2384:     case BGP_IPV6_NODE:
 2385:     case BGP_IPV6M_NODE:
 2386:     case RMAP_NODE:
 2387:     case OSPF_NODE:
 2388:     case OSPF6_NODE:
 2389:     case ISIS_NODE:
 2390:     case KEYCHAIN_NODE:
 2391:     case KEYCHAIN_KEY_NODE:
 2392:     case MASC_NODE:
 2393:     case VTY_NODE:
 2394:       vty_config_unlock (vty);
 2395:       vty->node = ENABLE_NODE;
 2396:       break;
 2397:     default:
 2398:       break;
 2399:     }
 2400:   return CMD_SUCCESS;
 2401: }
 2402: 
 2403: /* Show version. */
 2404: DEFUN (show_version,
 2405:        show_version_cmd,
 2406:        "show version",
 2407:        SHOW_STR
 2408:        "Displays zebra version\n")
 2409: {
 2410:   vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
 2411: 	   VTY_NEWLINE);
 2412:   vty_out (vty, "%s%s%s", QUAGGA_COPYRIGHT, GIT_INFO, VTY_NEWLINE);
 2413: 
 2414:   return CMD_SUCCESS;
 2415: }
 2416: 
 2417: /* Help display function for all node. */
 2418: DEFUN (config_help,
 2419:        config_help_cmd,
 2420:        "help",
 2421:        "Description of the interactive help system\n")
 2422: {
 2423:   vty_out (vty, 
 2424: 	   "Quagga VTY provides advanced help feature.  When you need help,%s\
 2425: anytime at the command line please press '?'.%s\
 2426: %s\
 2427: If nothing matches, the help list will be empty and you must backup%s\
 2428:  until entering a '?' shows the available options.%s\
 2429: Two styles of help are provided:%s\
 2430: 1. Full help is available when you are ready to enter a%s\
 2431: command argument (e.g. 'show ?') and describes each possible%s\
 2432: argument.%s\
 2433: 2. Partial help is provided when an abbreviated argument is entered%s\
 2434:    and you want to know what arguments match the input%s\
 2435:    (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
 2436: 	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
 2437: 	   VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
 2438:   return CMD_SUCCESS;
 2439: }
 2440: 
 2441: /* Help display function for all node. */
 2442: DEFUN (config_list,
 2443:        config_list_cmd,
 2444:        "list",
 2445:        "Print command list\n")
 2446: {
 2447:   unsigned int i;
 2448:   struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
 2449:   struct cmd_element *cmd;
 2450: 
 2451:   for (i = 0; i < vector_active (cnode->cmd_vector); i++)
 2452:     if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
 2453:         && !(cmd->attr == CMD_ATTR_DEPRECATED
 2454:              || cmd->attr == CMD_ATTR_HIDDEN))
 2455:       vty_out (vty, "  %s%s", cmd->string,
 2456: 	       VTY_NEWLINE);
 2457:   return CMD_SUCCESS;
 2458: }
 2459: 
 2460: /* Write current configuration into file. */
 2461: DEFUN (config_write_file, 
 2462:        config_write_file_cmd,
 2463:        "write file",  
 2464:        "Write running configuration to memory, network, or terminal\n"
 2465:        "Write to configuration file\n")
 2466: {
 2467:   unsigned int i;
 2468:   int fd;
 2469:   struct cmd_node *node;
 2470:   char *config_file;
 2471:   char *config_file_tmp = NULL;
 2472:   char *config_file_sav = NULL;
 2473:   int ret = CMD_WARNING;
 2474:   struct vty *file_vty;
 2475: 
 2476:   /* Check and see if we are operating under vtysh configuration */
 2477:   if (host.config == NULL)
 2478:     {
 2479:       vty_out (vty, "Can't save to configuration file, using vtysh.%s",
 2480: 	       VTY_NEWLINE);
 2481:       return CMD_WARNING;
 2482:     }
 2483: 
 2484:   /* Get filename. */
 2485:   config_file = host.config;
 2486:   
 2487:   config_file_sav =
 2488:     XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
 2489:   strcpy (config_file_sav, config_file);
 2490:   strcat (config_file_sav, CONF_BACKUP_EXT);
 2491: 
 2492: 
 2493:   config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
 2494:   sprintf (config_file_tmp, "%s.XXXXXX", config_file);
 2495:   
 2496:   /* Open file to configuration write. */
 2497:   fd = mkstemp (config_file_tmp);
 2498:   if (fd < 0)
 2499:     {
 2500:       vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
 2501: 	       VTY_NEWLINE);
 2502:       goto finished;
 2503:     }
 2504:   
 2505:   /* Make vty for configuration file. */
 2506:   file_vty = vty_new ();
 2507:   file_vty->fd = fd;
 2508:   file_vty->type = VTY_FILE;
 2509: 
 2510:   /* Config file header print. */
 2511:   vty_out (file_vty, "!\n! Zebra configuration saved from vty\n!   ");
 2512:   vty_time_print (file_vty, 1);
 2513:   vty_out (file_vty, "!\n");
 2514: 
 2515:   for (i = 0; i < vector_active (cmdvec); i++)
 2516:     if ((node = vector_slot (cmdvec, i)) && node->func)
 2517:       {
 2518: 	if ((*node->func) (file_vty))
 2519: 	  vty_out (file_vty, "!\n");
 2520:       }
 2521:   vty_close (file_vty);
 2522: 
 2523:   if (unlink (config_file_sav) != 0)
 2524:     if (errno != ENOENT)
 2525:       {
 2526: 	vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
 2527: 		 VTY_NEWLINE);
 2528:         goto finished;
 2529:       }
 2530:   if (link (config_file, config_file_sav) != 0)
 2531:     {
 2532:       vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
 2533: 	        VTY_NEWLINE);
 2534:       goto finished;
 2535:     }
 2536:   sync ();
 2537:   if (unlink (config_file) != 0)
 2538:     {
 2539:       vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
 2540: 	        VTY_NEWLINE);
 2541:       goto finished;
 2542:     }
 2543:   if (link (config_file_tmp, config_file) != 0)
 2544:     {
 2545:       vty_out (vty, "Can't save configuration file %s.%s", config_file,
 2546: 	       VTY_NEWLINE);
 2547:       goto finished;
 2548:     }
 2549:   sync ();
 2550:   
 2551:   if (chmod (config_file, CONFIGFILE_MASK) != 0)
 2552:     {
 2553:       vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s", 
 2554: 	config_file, safe_strerror(errno), errno, VTY_NEWLINE);
 2555:       goto finished;
 2556:     }
 2557: 
 2558:   vty_out (vty, "Configuration saved to %s%s", config_file,
 2559: 	   VTY_NEWLINE);
 2560:   ret = CMD_SUCCESS;
 2561: 
 2562: finished:
 2563:   unlink (config_file_tmp);
 2564:   XFREE (MTYPE_TMP, config_file_tmp);
 2565:   XFREE (MTYPE_TMP, config_file_sav);
 2566:   return ret;
 2567: }
 2568: 
 2569: ALIAS (config_write_file, 
 2570:        config_write_cmd,
 2571:        "write",  
 2572:        "Write running configuration to memory, network, or terminal\n")
 2573: 
 2574: ALIAS (config_write_file, 
 2575:        config_write_memory_cmd,
 2576:        "write memory",  
 2577:        "Write running configuration to memory, network, or terminal\n"
 2578:        "Write configuration to the file (same as write file)\n")
 2579: 
 2580: ALIAS (config_write_file, 
 2581:        copy_runningconfig_startupconfig_cmd,
 2582:        "copy running-config startup-config",  
 2583:        "Copy configuration\n"
 2584:        "Copy running config to... \n"
 2585:        "Copy running config to startup config (same as write file)\n")
 2586: 
 2587: /* Write current configuration into the terminal. */
 2588: DEFUN (config_write_terminal,
 2589:        config_write_terminal_cmd,
 2590:        "write terminal",
 2591:        "Write running configuration to memory, network, or terminal\n"
 2592:        "Write to terminal\n")
 2593: {
 2594:   unsigned int i;
 2595:   struct cmd_node *node;
 2596: 
 2597:   if (vty->type == VTY_SHELL_SERV)
 2598:     {
 2599:       for (i = 0; i < vector_active (cmdvec); i++)
 2600: 	if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
 2601: 	  {
 2602: 	    if ((*node->func) (vty))
 2603: 	      vty_out (vty, "!%s", VTY_NEWLINE);
 2604: 	  }
 2605:     }
 2606:   else
 2607:     {
 2608:       vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
 2609: 	       VTY_NEWLINE);
 2610:       vty_out (vty, "!%s", VTY_NEWLINE);
 2611: 
 2612:       for (i = 0; i < vector_active (cmdvec); i++)
 2613: 	if ((node = vector_slot (cmdvec, i)) && node->func)
 2614: 	  {
 2615: 	    if ((*node->func) (vty))
 2616: 	      vty_out (vty, "!%s", VTY_NEWLINE);
 2617: 	  }
 2618:       vty_out (vty, "end%s",VTY_NEWLINE);
 2619:     }
 2620:   return CMD_SUCCESS;
 2621: }
 2622: 
 2623: /* Write current configuration into the terminal. */
 2624: ALIAS (config_write_terminal,
 2625:        show_running_config_cmd,
 2626:        "show running-config",
 2627:        SHOW_STR
 2628:        "running configuration\n")
 2629: 
 2630: /* Write startup configuration into the terminal. */
 2631: DEFUN (show_startup_config,
 2632:        show_startup_config_cmd,
 2633:        "show startup-config",
 2634:        SHOW_STR
 2635:        "Contentes of startup configuration\n")
 2636: {
 2637:   char buf[BUFSIZ];
 2638:   FILE *confp;
 2639: 
 2640:   confp = fopen (host.config, "r");
 2641:   if (confp == NULL)
 2642:     {
 2643:       vty_out (vty, "Can't open configuration file [%s]%s",
 2644: 	       host.config, VTY_NEWLINE);
 2645:       return CMD_WARNING;
 2646:     }
 2647: 
 2648:   while (fgets (buf, BUFSIZ, confp))
 2649:     {
 2650:       char *cp = buf;
 2651: 
 2652:       while (*cp != '\r' && *cp != '\n' && *cp != '\0')
 2653: 	cp++;
 2654:       *cp = '\0';
 2655: 
 2656:       vty_out (vty, "%s%s", buf, VTY_NEWLINE);
 2657:     }
 2658: 
 2659:   fclose (confp);
 2660: 
 2661:   return CMD_SUCCESS;
 2662: }
 2663: 
 2664: /* Hostname configuration */
 2665: DEFUN (config_hostname, 
 2666:        hostname_cmd,
 2667:        "hostname WORD",
 2668:        "Set system's network name\n"
 2669:        "This system's network name\n")
 2670: {
 2671:   if (!isalpha((int) *argv[0]))
 2672:     {
 2673:       vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
 2674:       return CMD_WARNING;
 2675:     }
 2676: 
 2677:   if (host.name)
 2678:     XFREE (MTYPE_HOST, host.name);
 2679:     
 2680:   host.name = XSTRDUP (MTYPE_HOST, argv[0]);
 2681:   return CMD_SUCCESS;
 2682: }
 2683: 
 2684: DEFUN (config_no_hostname, 
 2685:        no_hostname_cmd,
 2686:        "no hostname [HOSTNAME]",
 2687:        NO_STR
 2688:        "Reset system's network name\n"
 2689:        "Host name of this router\n")
 2690: {
 2691:   if (host.name)
 2692:     XFREE (MTYPE_HOST, host.name);
 2693:   host.name = NULL;
 2694:   return CMD_SUCCESS;
 2695: }
 2696: 
 2697: /* VTY interface password set. */
 2698: DEFUN (config_password, password_cmd,
 2699:        "password (8|) WORD",
 2700:        "Assign the terminal connection password\n"
 2701:        "Specifies a HIDDEN password will follow\n"
 2702:        "dummy string \n"
 2703:        "The HIDDEN line password string\n")
 2704: {
 2705:   /* Argument check. */
 2706:   if (argc == 0)
 2707:     {
 2708:       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
 2709:       return CMD_WARNING;
 2710:     }
 2711: 
 2712:   if (argc == 2)
 2713:     {
 2714:       if (*argv[0] == '8')
 2715: 	{
 2716: 	  if (host.password)
 2717: 	    XFREE (MTYPE_HOST, host.password);
 2718: 	  host.password = NULL;
 2719: 	  if (host.password_encrypt)
 2720: 	    XFREE (MTYPE_HOST, host.password_encrypt);
 2721: 	  host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
 2722: 	  return CMD_SUCCESS;
 2723: 	}
 2724:       else
 2725: 	{
 2726: 	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
 2727: 	  return CMD_WARNING;
 2728: 	}
 2729:     }
 2730: 
 2731:   if (!isalnum ((int) *argv[0]))
 2732:     {
 2733:       vty_out (vty, 
 2734: 	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
 2735:       return CMD_WARNING;
 2736:     }
 2737: 
 2738:   if (host.password)
 2739:     XFREE (MTYPE_HOST, host.password);
 2740:   host.password = NULL;
 2741: 
 2742:   if (host.encrypt)
 2743:     {
 2744:       if (host.password_encrypt)
 2745: 	XFREE (MTYPE_HOST, host.password_encrypt);
 2746:       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
 2747:     }
 2748:   else
 2749:     host.password = XSTRDUP (MTYPE_HOST, argv[0]);
 2750: 
 2751:   return CMD_SUCCESS;
 2752: }
 2753: 
 2754: ALIAS (config_password, password_text_cmd,
 2755:        "password LINE",
 2756:        "Assign the terminal connection password\n"
 2757:        "The UNENCRYPTED (cleartext) line password\n")
 2758: 
 2759: /* VTY enable password set. */
 2760: DEFUN (config_enable_password, enable_password_cmd,
 2761:        "enable password (8|) WORD",
 2762:        "Modify enable password parameters\n"
 2763:        "Assign the privileged level password\n"
 2764:        "Specifies a HIDDEN password will follow\n"
 2765:        "dummy string \n"
 2766:        "The HIDDEN 'enable' password string\n")
 2767: {
 2768:   /* Argument check. */
 2769:   if (argc == 0)
 2770:     {
 2771:       vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
 2772:       return CMD_WARNING;
 2773:     }
 2774: 
 2775:   /* Crypt type is specified. */
 2776:   if (argc == 2)
 2777:     {
 2778:       if (*argv[0] == '8')
 2779: 	{
 2780: 	  if (host.enable)
 2781: 	    XFREE (MTYPE_HOST, host.enable);
 2782: 	  host.enable = NULL;
 2783: 
 2784: 	  if (host.enable_encrypt)
 2785: 	    XFREE (MTYPE_HOST, host.enable_encrypt);
 2786: 	  host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
 2787: 
 2788: 	  return CMD_SUCCESS;
 2789: 	}
 2790:       else
 2791: 	{
 2792: 	  vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
 2793: 	  return CMD_WARNING;
 2794: 	}
 2795:     }
 2796: 
 2797:   if (!isalnum ((int) *argv[0]))
 2798:     {
 2799:       vty_out (vty, 
 2800: 	       "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
 2801:       return CMD_WARNING;
 2802:     }
 2803: 
 2804:   if (host.enable)
 2805:     XFREE (MTYPE_HOST, host.enable);
 2806:   host.enable = NULL;
 2807: 
 2808:   /* Plain password input. */
 2809:   if (host.encrypt)
 2810:     {
 2811:       if (host.enable_encrypt)
 2812: 	XFREE (MTYPE_HOST, host.enable_encrypt);
 2813:       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
 2814:     }
 2815:   else
 2816:     host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
 2817: 
 2818:   return CMD_SUCCESS;
 2819: }
 2820: 
 2821: ALIAS (config_enable_password,
 2822:        enable_password_text_cmd,
 2823:        "enable password LINE",
 2824:        "Modify enable password parameters\n"
 2825:        "Assign the privileged level password\n"
 2826:        "The UNENCRYPTED (cleartext) 'enable' password\n")
 2827: 
 2828: /* VTY enable password delete. */
 2829: DEFUN (no_config_enable_password, no_enable_password_cmd,
 2830:        "no enable password",
 2831:        NO_STR
 2832:        "Modify enable password parameters\n"
 2833:        "Assign the privileged level password\n")
 2834: {
 2835:   if (host.enable)
 2836:     XFREE (MTYPE_HOST, host.enable);
 2837:   host.enable = NULL;
 2838: 
 2839:   if (host.enable_encrypt)
 2840:     XFREE (MTYPE_HOST, host.enable_encrypt);
 2841:   host.enable_encrypt = NULL;
 2842: 
 2843:   return CMD_SUCCESS;
 2844: }
 2845: 	
 2846: DEFUN (service_password_encrypt,
 2847:        service_password_encrypt_cmd,
 2848:        "service password-encryption",
 2849:        "Set up miscellaneous service\n"
 2850:        "Enable encrypted passwords\n")
 2851: {
 2852:   if (host.encrypt)
 2853:     return CMD_SUCCESS;
 2854: 
 2855:   host.encrypt = 1;
 2856: 
 2857:   if (host.password)
 2858:     {
 2859:       if (host.password_encrypt)
 2860: 	XFREE (MTYPE_HOST, host.password_encrypt);
 2861:       host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
 2862:     }
 2863:   if (host.enable)
 2864:     {
 2865:       if (host.enable_encrypt)
 2866: 	XFREE (MTYPE_HOST, host.enable_encrypt);
 2867:       host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
 2868:     }
 2869: 
 2870:   return CMD_SUCCESS;
 2871: }
 2872: 
 2873: DEFUN (no_service_password_encrypt,
 2874:        no_service_password_encrypt_cmd,
 2875:        "no service password-encryption",
 2876:        NO_STR
 2877:        "Set up miscellaneous service\n"
 2878:        "Enable encrypted passwords\n")
 2879: {
 2880:   if (! host.encrypt)
 2881:     return CMD_SUCCESS;
 2882: 
 2883:   host.encrypt = 0;
 2884: 
 2885:   if (host.password_encrypt)
 2886:     XFREE (MTYPE_HOST, host.password_encrypt);
 2887:   host.password_encrypt = NULL;
 2888: 
 2889:   if (host.enable_encrypt)
 2890:     XFREE (MTYPE_HOST, host.enable_encrypt);
 2891:   host.enable_encrypt = NULL;
 2892: 
 2893:   return CMD_SUCCESS;
 2894: }
 2895: 
 2896: DEFUN (config_terminal_length, config_terminal_length_cmd,
 2897:        "terminal length <0-512>",
 2898:        "Set terminal line parameters\n"
 2899:        "Set number of lines on a screen\n"
 2900:        "Number of lines on screen (0 for no pausing)\n")
 2901: {
 2902:   int lines;
 2903:   char *endptr = NULL;
 2904: 
 2905:   lines = strtol (argv[0], &endptr, 10);
 2906:   if (lines < 0 || lines > 512 || *endptr != '\0')
 2907:     {
 2908:       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
 2909:       return CMD_WARNING;
 2910:     }
 2911:   vty->lines = lines;
 2912: 
 2913:   return CMD_SUCCESS;
 2914: }
 2915: 
 2916: DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
 2917:        "terminal no length",
 2918:        "Set terminal line parameters\n"
 2919:        NO_STR
 2920:        "Set number of lines on a screen\n")
 2921: {
 2922:   vty->lines = -1;
 2923:   return CMD_SUCCESS;
 2924: }
 2925: 
 2926: DEFUN (service_terminal_length, service_terminal_length_cmd,
 2927:        "service terminal-length <0-512>",
 2928:        "Set up miscellaneous service\n"
 2929:        "System wide terminal length configuration\n"
 2930:        "Number of lines of VTY (0 means no line control)\n")
 2931: {
 2932:   int lines;
 2933:   char *endptr = NULL;
 2934: 
 2935:   lines = strtol (argv[0], &endptr, 10);
 2936:   if (lines < 0 || lines > 512 || *endptr != '\0')
 2937:     {
 2938:       vty_out (vty, "length is malformed%s", VTY_NEWLINE);
 2939:       return CMD_WARNING;
 2940:     }
 2941:   host.lines = lines;
 2942: 
 2943:   return CMD_SUCCESS;
 2944: }
 2945: 
 2946: DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
 2947:        "no service terminal-length [<0-512>]",
 2948:        NO_STR
 2949:        "Set up miscellaneous service\n"
 2950:        "System wide terminal length configuration\n"
 2951:        "Number of lines of VTY (0 means no line control)\n")
 2952: {
 2953:   host.lines = -1;
 2954:   return CMD_SUCCESS;
 2955: }
 2956: 
 2957: DEFUN_HIDDEN (do_echo,
 2958: 	      echo_cmd,
 2959: 	      "echo .MESSAGE",
 2960: 	      "Echo a message back to the vty\n"
 2961: 	      "The message to echo\n")
 2962: {
 2963:   char *message;
 2964: 
 2965:   vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
 2966: 	   VTY_NEWLINE);
 2967:   if (message)
 2968:     XFREE(MTYPE_TMP, message);
 2969:   return CMD_SUCCESS;
 2970: }
 2971: 
 2972: DEFUN (config_logmsg,
 2973:        config_logmsg_cmd,
 2974:        "logmsg "LOG_LEVELS" .MESSAGE",
 2975:        "Send a message to enabled logging destinations\n"
 2976:        LOG_LEVEL_DESC
 2977:        "The message to send\n")
 2978: {
 2979:   int level;
 2980:   char *message;
 2981: 
 2982:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
 2983:     return CMD_ERR_NO_MATCH;
 2984: 
 2985:   zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
 2986:   if (message)
 2987:     XFREE(MTYPE_TMP, message);
 2988:   return CMD_SUCCESS;
 2989: }
 2990: 
 2991: DEFUN (show_logging,
 2992:        show_logging_cmd,
 2993:        "show logging",
 2994:        SHOW_STR
 2995:        "Show current logging configuration\n")
 2996: {
 2997:   struct zlog *zl = zlog_default;
 2998: 
 2999:   vty_out (vty, "Syslog logging: ");
 3000:   if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
 3001:     vty_out (vty, "disabled");
 3002:   else
 3003:     vty_out (vty, "level %s, facility %s, ident %s",
 3004: 	     zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
 3005: 	     facility_name(zl->facility), zl->ident);
 3006:   vty_out (vty, "%s", VTY_NEWLINE);
 3007: 
 3008:   vty_out (vty, "Stdout logging: ");
 3009:   if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
 3010:     vty_out (vty, "disabled");
 3011:   else
 3012:     vty_out (vty, "level %s",
 3013: 	     zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
 3014:   vty_out (vty, "%s", VTY_NEWLINE);
 3015: 
 3016:   vty_out (vty, "Monitor logging: ");
 3017:   if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
 3018:     vty_out (vty, "disabled");
 3019:   else
 3020:     vty_out (vty, "level %s",
 3021: 	     zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
 3022:   vty_out (vty, "%s", VTY_NEWLINE);
 3023: 
 3024:   vty_out (vty, "File logging: ");
 3025:   if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
 3026:       !zl->fp)
 3027:     vty_out (vty, "disabled");
 3028:   else
 3029:     vty_out (vty, "level %s, filename %s",
 3030: 	     zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
 3031: 	     zl->filename);
 3032:   vty_out (vty, "%s", VTY_NEWLINE);
 3033: 
 3034:   vty_out (vty, "Protocol name: %s%s",
 3035:   	   zlog_proto_names[zl->protocol], VTY_NEWLINE);
 3036:   vty_out (vty, "Record priority: %s%s",
 3037:   	   (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
 3038:   vty_out (vty, "Timestamp precision: %d%s",
 3039: 	   zl->timestamp_precision, VTY_NEWLINE);
 3040: 
 3041:   return CMD_SUCCESS;
 3042: }
 3043: 
 3044: DEFUN (config_log_stdout,
 3045:        config_log_stdout_cmd,
 3046:        "log stdout",
 3047:        "Logging control\n"
 3048:        "Set stdout logging level\n")
 3049: {
 3050:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
 3051:   return CMD_SUCCESS;
 3052: }
 3053: 
 3054: DEFUN (config_log_stdout_level,
 3055:        config_log_stdout_level_cmd,
 3056:        "log stdout "LOG_LEVELS,
 3057:        "Logging control\n"
 3058:        "Set stdout logging level\n"
 3059:        LOG_LEVEL_DESC)
 3060: {
 3061:   int level;
 3062: 
 3063:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
 3064:     return CMD_ERR_NO_MATCH;
 3065:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
 3066:   return CMD_SUCCESS;
 3067: }
 3068: 
 3069: DEFUN (no_config_log_stdout,
 3070:        no_config_log_stdout_cmd,
 3071:        "no log stdout [LEVEL]",
 3072:        NO_STR
 3073:        "Logging control\n"
 3074:        "Cancel logging to stdout\n"
 3075:        "Logging level\n")
 3076: {
 3077:   zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
 3078:   return CMD_SUCCESS;
 3079: }
 3080: 
 3081: DEFUN (config_log_monitor,
 3082:        config_log_monitor_cmd,
 3083:        "log monitor",
 3084:        "Logging control\n"
 3085:        "Set terminal line (monitor) logging level\n")
 3086: {
 3087:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
 3088:   return CMD_SUCCESS;
 3089: }
 3090: 
 3091: DEFUN (config_log_monitor_level,
 3092:        config_log_monitor_level_cmd,
 3093:        "log monitor "LOG_LEVELS,
 3094:        "Logging control\n"
 3095:        "Set terminal line (monitor) logging level\n"
 3096:        LOG_LEVEL_DESC)
 3097: {
 3098:   int level;
 3099: 
 3100:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
 3101:     return CMD_ERR_NO_MATCH;
 3102:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
 3103:   return CMD_SUCCESS;
 3104: }
 3105: 
 3106: DEFUN (no_config_log_monitor,
 3107:        no_config_log_monitor_cmd,
 3108:        "no log monitor [LEVEL]",
 3109:        NO_STR
 3110:        "Logging control\n"
 3111:        "Disable terminal line (monitor) logging\n"
 3112:        "Logging level\n")
 3113: {
 3114:   zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
 3115:   return CMD_SUCCESS;
 3116: }
 3117: 
 3118: static int
 3119: set_log_file(struct vty *vty, const char *fname, int loglevel)
 3120: {
 3121:   int ret;
 3122:   char *p = NULL;
 3123:   const char *fullpath;
 3124:   
 3125:   /* Path detection. */
 3126:   if (! IS_DIRECTORY_SEP (*fname))
 3127:     {
 3128:       char cwd[MAXPATHLEN+1];
 3129:       cwd[MAXPATHLEN] = '\0';
 3130:       
 3131:       if (getcwd (cwd, MAXPATHLEN) == NULL)
 3132:         {
 3133:           zlog_err ("config_log_file: Unable to alloc mem!");
 3134:           return CMD_WARNING;
 3135:         }
 3136:       
 3137:       if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
 3138:           == NULL)
 3139:         {
 3140:           zlog_err ("config_log_file: Unable to alloc mem!");
 3141:           return CMD_WARNING;
 3142:         }
 3143:       sprintf (p, "%s/%s", cwd, fname);
 3144:       fullpath = p;
 3145:     }
 3146:   else
 3147:     fullpath = fname;
 3148: 
 3149:   ret = zlog_set_file (NULL, fullpath, loglevel);
 3150: 
 3151:   if (p)
 3152:     XFREE (MTYPE_TMP, p);
 3153: 
 3154:   if (!ret)
 3155:     {
 3156:       vty_out (vty, "can't open logfile %s\n", fname);
 3157:       return CMD_WARNING;
 3158:     }
 3159: 
 3160:   if (host.logfile)
 3161:     XFREE (MTYPE_HOST, host.logfile);
 3162: 
 3163:   host.logfile = XSTRDUP (MTYPE_HOST, fname);
 3164: 
 3165:   return CMD_SUCCESS;
 3166: }
 3167: 
 3168: DEFUN (config_log_file,
 3169:        config_log_file_cmd,
 3170:        "log file FILENAME",
 3171:        "Logging control\n"
 3172:        "Logging to file\n"
 3173:        "Logging filename\n")
 3174: {
 3175:   return set_log_file(vty, argv[0], zlog_default->default_lvl);
 3176: }
 3177: 
 3178: DEFUN (config_log_file_level,
 3179:        config_log_file_level_cmd,
 3180:        "log file FILENAME "LOG_LEVELS,
 3181:        "Logging control\n"
 3182:        "Logging to file\n"
 3183:        "Logging filename\n"
 3184:        LOG_LEVEL_DESC)
 3185: {
 3186:   int level;
 3187: 
 3188:   if ((level = level_match(argv[1])) == ZLOG_DISABLED)
 3189:     return CMD_ERR_NO_MATCH;
 3190:   return set_log_file(vty, argv[0], level);
 3191: }
 3192: 
 3193: DEFUN (no_config_log_file,
 3194:        no_config_log_file_cmd,
 3195:        "no log file [FILENAME]",
 3196:        NO_STR
 3197:        "Logging control\n"
 3198:        "Cancel logging to file\n"
 3199:        "Logging file name\n")
 3200: {
 3201:   zlog_reset_file (NULL);
 3202: 
 3203:   if (host.logfile)
 3204:     XFREE (MTYPE_HOST, host.logfile);
 3205: 
 3206:   host.logfile = NULL;
 3207: 
 3208:   return CMD_SUCCESS;
 3209: }
 3210: 
 3211: ALIAS (no_config_log_file,
 3212:        no_config_log_file_level_cmd,
 3213:        "no log file FILENAME LEVEL",
 3214:        NO_STR
 3215:        "Logging control\n"
 3216:        "Cancel logging to file\n"
 3217:        "Logging file name\n"
 3218:        "Logging level\n")
 3219: 
 3220: DEFUN (config_log_syslog,
 3221:        config_log_syslog_cmd,
 3222:        "log syslog",
 3223:        "Logging control\n"
 3224:        "Set syslog logging level\n")
 3225: {
 3226:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
 3227:   return CMD_SUCCESS;
 3228: }
 3229: 
 3230: DEFUN (config_log_syslog_level,
 3231:        config_log_syslog_level_cmd,
 3232:        "log syslog "LOG_LEVELS,
 3233:        "Logging control\n"
 3234:        "Set syslog logging level\n"
 3235:        LOG_LEVEL_DESC)
 3236: {
 3237:   int level;
 3238: 
 3239:   if ((level = level_match(argv[0])) == ZLOG_DISABLED)
 3240:     return CMD_ERR_NO_MATCH;
 3241:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
 3242:   return CMD_SUCCESS;
 3243: }
 3244: 
 3245: DEFUN_DEPRECATED (config_log_syslog_facility,
 3246: 		  config_log_syslog_facility_cmd,
 3247: 		  "log syslog facility "LOG_FACILITIES,
 3248: 		  "Logging control\n"
 3249: 		  "Logging goes to syslog\n"
 3250: 		  "(Deprecated) Facility parameter for syslog messages\n"
 3251: 		  LOG_FACILITY_DESC)
 3252: {
 3253:   int facility;
 3254: 
 3255:   if ((facility = facility_match(argv[0])) < 0)
 3256:     return CMD_ERR_NO_MATCH;
 3257: 
 3258:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
 3259:   zlog_default->facility = facility;
 3260:   return CMD_SUCCESS;
 3261: }
 3262: 
 3263: DEFUN (no_config_log_syslog,
 3264:        no_config_log_syslog_cmd,
 3265:        "no log syslog [LEVEL]",
 3266:        NO_STR
 3267:        "Logging control\n"
 3268:        "Cancel logging to syslog\n"
 3269:        "Logging level\n")
 3270: {
 3271:   zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
 3272:   return CMD_SUCCESS;
 3273: }
 3274: 
 3275: ALIAS (no_config_log_syslog,
 3276:        no_config_log_syslog_facility_cmd,
 3277:        "no log syslog facility "LOG_FACILITIES,
 3278:        NO_STR
 3279:        "Logging control\n"
 3280:        "Logging goes to syslog\n"
 3281:        "Facility parameter for syslog messages\n"
 3282:        LOG_FACILITY_DESC)
 3283: 
 3284: DEFUN (config_log_facility,
 3285:        config_log_facility_cmd,
 3286:        "log facility "LOG_FACILITIES,
 3287:        "Logging control\n"
 3288:        "Facility parameter for syslog messages\n"
 3289:        LOG_FACILITY_DESC)
 3290: {
 3291:   int facility;
 3292: 
 3293:   if ((facility = facility_match(argv[0])) < 0)
 3294:     return CMD_ERR_NO_MATCH;
 3295:   zlog_default->facility = facility;
 3296:   return CMD_SUCCESS;
 3297: }
 3298: 
 3299: DEFUN (no_config_log_facility,
 3300:        no_config_log_facility_cmd,
 3301:        "no log facility [FACILITY]",
 3302:        NO_STR
 3303:        "Logging control\n"
 3304:        "Reset syslog facility to default (daemon)\n"
 3305:        "Syslog facility\n")
 3306: {
 3307:   zlog_default->facility = LOG_DAEMON;
 3308:   return CMD_SUCCESS;
 3309: }
 3310: 
 3311: DEFUN_DEPRECATED (config_log_trap,
 3312: 		  config_log_trap_cmd,
 3313: 		  "log trap "LOG_LEVELS,
 3314: 		  "Logging control\n"
 3315: 		  "(Deprecated) Set logging level and default for all destinations\n"
 3316: 		  LOG_LEVEL_DESC)
 3317: {
 3318:   int new_level ;
 3319:   int i;
 3320:   
 3321:   if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
 3322:     return CMD_ERR_NO_MATCH;
 3323: 
 3324:   zlog_default->default_lvl = new_level;
 3325:   for (i = 0; i < ZLOG_NUM_DESTS; i++)
 3326:     if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
 3327:       zlog_default->maxlvl[i] = new_level;
 3328:   return CMD_SUCCESS;
 3329: }
 3330: 
 3331: DEFUN_DEPRECATED (no_config_log_trap,
 3332: 		  no_config_log_trap_cmd,
 3333: 		  "no log trap [LEVEL]",
 3334: 		  NO_STR
 3335: 		  "Logging control\n"
 3336: 		  "Permit all logging information\n"
 3337: 		  "Logging level\n")
 3338: {
 3339:   zlog_default->default_lvl = LOG_DEBUG;
 3340:   return CMD_SUCCESS;
 3341: }
 3342: 
 3343: DEFUN (config_log_record_priority,
 3344:        config_log_record_priority_cmd,
 3345:        "log record-priority",
 3346:        "Logging control\n"
 3347:        "Log the priority of the message within the message\n")
 3348: {
 3349:   zlog_default->record_priority = 1 ;
 3350:   return CMD_SUCCESS;
 3351: }
 3352: 
 3353: DEFUN (no_config_log_record_priority,
 3354:        no_config_log_record_priority_cmd,
 3355:        "no log record-priority",
 3356:        NO_STR
 3357:        "Logging control\n"
 3358:        "Do not log the priority of the message within the message\n")
 3359: {
 3360:   zlog_default->record_priority = 0 ;
 3361:   return CMD_SUCCESS;
 3362: }
 3363: 
 3364: DEFUN (config_log_timestamp_precision,
 3365:        config_log_timestamp_precision_cmd,
 3366:        "log timestamp precision <0-6>",
 3367:        "Logging control\n"
 3368:        "Timestamp configuration\n"
 3369:        "Set the timestamp precision\n"
 3370:        "Number of subsecond digits\n")
 3371: {
 3372:   if (argc != 1)
 3373:     {
 3374:       vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
 3375:       return CMD_WARNING;
 3376:     }
 3377: 
 3378:   VTY_GET_INTEGER_RANGE("Timestamp Precision",
 3379:   			zlog_default->timestamp_precision, argv[0], 0, 6);
 3380:   return CMD_SUCCESS;
 3381: }
 3382: 
 3383: DEFUN (no_config_log_timestamp_precision,
 3384:        no_config_log_timestamp_precision_cmd,
 3385:        "no log timestamp precision",
 3386:        NO_STR
 3387:        "Logging control\n"
 3388:        "Timestamp configuration\n"
 3389:        "Reset the timestamp precision to the default value of 0\n")
 3390: {
 3391:   zlog_default->timestamp_precision = 0 ;
 3392:   return CMD_SUCCESS;
 3393: }
 3394: 
 3395: DEFUN (banner_motd_file,
 3396:        banner_motd_file_cmd,
 3397:        "banner motd file [FILE]",
 3398:        "Set banner\n"
 3399:        "Banner for motd\n"
 3400:        "Banner from a file\n"
 3401:        "Filename\n")
 3402: {
 3403:   if (host.motdfile)
 3404:     XFREE (MTYPE_HOST, host.motdfile);
 3405:   host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
 3406: 
 3407:   return CMD_SUCCESS;
 3408: }
 3409: 
 3410: DEFUN (banner_motd_default,
 3411:        banner_motd_default_cmd,
 3412:        "banner motd default",
 3413:        "Set banner string\n"
 3414:        "Strings for motd\n"
 3415:        "Default string\n")
 3416: {
 3417:   host.motd = default_motd;
 3418:   return CMD_SUCCESS;
 3419: }
 3420: 
 3421: DEFUN (no_banner_motd,
 3422:        no_banner_motd_cmd,
 3423:        "no banner motd",
 3424:        NO_STR
 3425:        "Set banner string\n"
 3426:        "Strings for motd\n")
 3427: {
 3428:   host.motd = NULL;
 3429:   if (host.motdfile) 
 3430:     XFREE (MTYPE_HOST, host.motdfile);
 3431:   host.motdfile = NULL;
 3432:   return CMD_SUCCESS;
 3433: }
 3434: 
 3435: /* Set config filename.  Called from vty.c */
 3436: void
 3437: host_config_set (char *filename)
 3438: {
 3439:   if (host.config)
 3440:     XFREE (MTYPE_HOST, host.config);
 3441:   host.config = XSTRDUP (MTYPE_HOST, filename);
 3442: }
 3443: 
 3444: void
 3445: install_default (enum node_type node)
 3446: {
 3447:   install_element (node, &config_exit_cmd);
 3448:   install_element (node, &config_quit_cmd);
 3449:   install_element (node, &config_end_cmd);
 3450:   install_element (node, &config_help_cmd);
 3451:   install_element (node, &config_list_cmd);
 3452: 
 3453:   install_element (node, &config_write_terminal_cmd);
 3454:   install_element (node, &config_write_file_cmd);
 3455:   install_element (node, &config_write_memory_cmd);
 3456:   install_element (node, &config_write_cmd);
 3457:   install_element (node, &show_running_config_cmd);
 3458: }
 3459: 
 3460: /* Initialize command interface. Install basic nodes and commands. */
 3461: void
 3462: cmd_init (int terminal)
 3463: {
 3464:   command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
 3465:   desc_cr.cmd = command_cr;
 3466:   desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
 3467: 
 3468:   /* Allocate initial top vector of commands. */
 3469:   cmdvec = vector_init (VECTOR_MIN_SIZE);
 3470: 
 3471:   /* Default host value settings. */
 3472:   host.name = NULL;
 3473:   host.password = NULL;
 3474:   host.enable = NULL;
 3475:   host.logfile = NULL;
 3476:   host.config = NULL;
 3477:   host.lines = -1;
 3478:   host.motd = default_motd;
 3479:   host.motdfile = NULL;
 3480: 
 3481:   /* Install top nodes. */
 3482:   install_node (&view_node, NULL);
 3483:   install_node (&enable_node, NULL);
 3484:   install_node (&auth_node, NULL);
 3485:   install_node (&auth_enable_node, NULL);
 3486:   install_node (&restricted_node, NULL);
 3487:   install_node (&config_node, config_write_host);
 3488: 
 3489:   /* Each node's basic commands. */
 3490:   install_element (VIEW_NODE, &show_version_cmd);
 3491:   if (terminal)
 3492:     {
 3493:       install_element (VIEW_NODE, &config_list_cmd);
 3494:       install_element (VIEW_NODE, &config_exit_cmd);
 3495:       install_element (VIEW_NODE, &config_quit_cmd);
 3496:       install_element (VIEW_NODE, &config_help_cmd);
 3497:       install_element (VIEW_NODE, &config_enable_cmd);
 3498:       install_element (VIEW_NODE, &config_terminal_length_cmd);
 3499:       install_element (VIEW_NODE, &config_terminal_no_length_cmd);
 3500:       install_element (VIEW_NODE, &show_logging_cmd);
 3501:       install_element (VIEW_NODE, &echo_cmd);
 3502: 
 3503:       install_element (RESTRICTED_NODE, &config_list_cmd);
 3504:       install_element (RESTRICTED_NODE, &config_exit_cmd);
 3505:       install_element (RESTRICTED_NODE, &config_quit_cmd);
 3506:       install_element (RESTRICTED_NODE, &config_help_cmd);
 3507:       install_element (RESTRICTED_NODE, &config_enable_cmd);
 3508:       install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
 3509:       install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
 3510:       install_element (RESTRICTED_NODE, &echo_cmd);
 3511:     }
 3512: 
 3513:   if (terminal)
 3514:     {
 3515:       install_default (ENABLE_NODE);
 3516:       install_element (ENABLE_NODE, &config_disable_cmd);
 3517:       install_element (ENABLE_NODE, &config_terminal_cmd);
 3518:       install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
 3519:     }
 3520:   install_element (ENABLE_NODE, &show_startup_config_cmd);
 3521:   install_element (ENABLE_NODE, &show_version_cmd);
 3522: 
 3523:   if (terminal)
 3524:     {
 3525:       install_element (ENABLE_NODE, &config_terminal_length_cmd);
 3526:       install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
 3527:       install_element (ENABLE_NODE, &show_logging_cmd);
 3528:       install_element (ENABLE_NODE, &echo_cmd);
 3529:       install_element (ENABLE_NODE, &config_logmsg_cmd);
 3530: 
 3531:       install_default (CONFIG_NODE);
 3532:     }
 3533:   
 3534:   install_element (CONFIG_NODE, &hostname_cmd);
 3535:   install_element (CONFIG_NODE, &no_hostname_cmd);
 3536: 
 3537:   if (terminal)
 3538:     {
 3539:       install_element (CONFIG_NODE, &password_cmd);
 3540:       install_element (CONFIG_NODE, &password_text_cmd);
 3541:       install_element (CONFIG_NODE, &enable_password_cmd);
 3542:       install_element (CONFIG_NODE, &enable_password_text_cmd);
 3543:       install_element (CONFIG_NODE, &no_enable_password_cmd);
 3544: 
 3545:       install_element (CONFIG_NODE, &config_log_stdout_cmd);
 3546:       install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
 3547:       install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
 3548:       install_element (CONFIG_NODE, &config_log_monitor_cmd);
 3549:       install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
 3550:       install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
 3551:       install_element (CONFIG_NODE, &config_log_file_cmd);
 3552:       install_element (CONFIG_NODE, &config_log_file_level_cmd);
 3553:       install_element (CONFIG_NODE, &no_config_log_file_cmd);
 3554:       install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
 3555:       install_element (CONFIG_NODE, &config_log_syslog_cmd);
 3556:       install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
 3557:       install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
 3558:       install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
 3559:       install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
 3560:       install_element (CONFIG_NODE, &config_log_facility_cmd);
 3561:       install_element (CONFIG_NODE, &no_config_log_facility_cmd);
 3562:       install_element (CONFIG_NODE, &config_log_trap_cmd);
 3563:       install_element (CONFIG_NODE, &no_config_log_trap_cmd);
 3564:       install_element (CONFIG_NODE, &config_log_record_priority_cmd);
 3565:       install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
 3566:       install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
 3567:       install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
 3568:       install_element (CONFIG_NODE, &service_password_encrypt_cmd);
 3569:       install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
 3570:       install_element (CONFIG_NODE, &banner_motd_default_cmd);
 3571:       install_element (CONFIG_NODE, &banner_motd_file_cmd);
 3572:       install_element (CONFIG_NODE, &no_banner_motd_cmd);
 3573:       install_element (CONFIG_NODE, &service_terminal_length_cmd);
 3574:       install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
 3575: 
 3576:       install_element (VIEW_NODE, &show_thread_cpu_cmd);
 3577:       install_element (ENABLE_NODE, &show_thread_cpu_cmd);
 3578:       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
 3579:       
 3580:       install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
 3581:       install_element (VIEW_NODE, &show_work_queues_cmd);
 3582:       install_element (ENABLE_NODE, &show_work_queues_cmd);
 3583:     }
 3584:   srand(time(NULL));
 3585: }
 3586: 
 3587: void
 3588: cmd_terminate ()
 3589: {
 3590:   unsigned int i, j, k, l;
 3591:   struct cmd_node *cmd_node;
 3592:   struct cmd_element *cmd_element;
 3593:   struct desc *desc;
 3594:   vector cmd_node_v, cmd_element_v, desc_v;
 3595: 
 3596:   if (cmdvec)
 3597:     {
 3598:       for (i = 0; i < vector_active (cmdvec); i++) 
 3599:         if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
 3600:           {
 3601:             cmd_node_v = cmd_node->cmd_vector;
 3602: 
 3603:             for (j = 0; j < vector_active (cmd_node_v); j++)
 3604:               if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
 3605:                   cmd_element->strvec != NULL)
 3606:                 {
 3607:                   cmd_element_v = cmd_element->strvec;
 3608: 
 3609:                   for (k = 0; k < vector_active (cmd_element_v); k++)
 3610:                     if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
 3611:                       {
 3612:                         for (l = 0; l < vector_active (desc_v); l++)
 3613:                           if ((desc = vector_slot (desc_v, l)) != NULL)
 3614:                             {
 3615:                               if (desc->cmd)
 3616:                                 XFREE (MTYPE_STRVEC, desc->cmd);
 3617:                               if (desc->str)
 3618:                                 XFREE (MTYPE_STRVEC, desc->str);
 3619: 
 3620:                               XFREE (MTYPE_DESC, desc);
 3621:                             }
 3622:                         vector_free (desc_v);
 3623:                       }
 3624: 
 3625:                   cmd_element->strvec = NULL;
 3626:                   vector_free (cmd_element_v);
 3627:                 }
 3628: 
 3629:             vector_free (cmd_node_v);
 3630:           }
 3631: 
 3632:       vector_free (cmdvec);
 3633:       cmdvec = NULL;
 3634:     }
 3635: 
 3636:   if (command_cr)
 3637:     XFREE(MTYPE_STRVEC, command_cr);
 3638:   if (desc_cr.str)
 3639:     XFREE(MTYPE_STRVEC, desc_cr.str);
 3640:   if (host.name)
 3641:     XFREE (MTYPE_HOST, host.name);
 3642:   if (host.password)
 3643:     XFREE (MTYPE_HOST, host.password);
 3644:   if (host.password_encrypt)
 3645:     XFREE (MTYPE_HOST, host.password_encrypt);
 3646:   if (host.enable)
 3647:     XFREE (MTYPE_HOST, host.enable);
 3648:   if (host.enable_encrypt)
 3649:     XFREE (MTYPE_HOST, host.enable_encrypt);
 3650:   if (host.logfile)
 3651:     XFREE (MTYPE_HOST, host.logfile);
 3652:   if (host.motdfile)
 3653:     XFREE (MTYPE_HOST, host.motdfile);
 3654:   if (host.config)
 3655:     XFREE (MTYPE_HOST, host.config);
 3656: }

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