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