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