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