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