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