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