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