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