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