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