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