blob: a0824d39776068e497078870429e5c53f982dd80 [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
Jaroslav Škarvada2b82c1c2015-11-11 16:02:54 +010021Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22Boston, MA 02110-1301, USA. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020023
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
Sylvain Munaut4d8eea42012-12-28 11:58:23 +010027#include <stdbool.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020028#include <syslog.h>
29#include <errno.h>
30#define _XOPEN_SOURCE
31#include <unistd.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020032#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 Weltea99d45a2015-11-12 13:48:23 +010042#include <osmocom/core/utils.h>
Harald Welte3fb0b6f2010-05-19 19:02:52 +020043
Harald Weltee881b1b2011-08-17 18:52:30 +020044/*! \addtogroup command
Harald Welte96e2a002017-06-12 21:44:18 +020045 * @{
Neels Hofmeyr87e45502017-06-20 00:17:59 +020046 * VTY command handling
Harald Welte7acb30c2011-08-17 17:13:48 +020047 */
48/*! \file command.c */
49
Harald Welte3fb0b6f2010-05-19 19:02:52 +020050#define CONFIGFILE_MASK 022
51
52void *tall_vty_cmd_ctx;
53
54/* Command vector which includes some level of command lists. Normally
55 each daemon maintains each own cmdvec. */
56vector cmdvec;
57
58/* Host information structure. */
59struct host host;
60
61/* Standard command node structures. */
62struct cmd_node auth_node = {
63 AUTH_NODE,
64 "Password: ",
65};
66
67struct cmd_node view_node = {
68 VIEW_NODE,
69 "%s> ",
70};
71
72struct cmd_node auth_enable_node = {
73 AUTH_ENABLE_NODE,
74 "Password: ",
75};
76
77struct cmd_node enable_node = {
78 ENABLE_NODE,
79 "%s# ",
80};
81
82struct cmd_node config_node = {
83 CONFIG_NODE,
84 "%s(config)# ",
85 1
86};
87
88/* Default motd string. */
89const char *default_motd = "";
90
Neels Hofmeyr87e45502017-06-20 00:17:59 +020091/*! print the version (and optionally copyright) information
Harald Welte7acb30c2011-08-17 17:13:48 +020092 *
93 * This is called from main when a daemon is invoked with -v or --version. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +020094void print_version(int print_copyright)
95{
Harald Welte237f6242010-05-25 23:00:45 +020096 printf("%s version %s\n", host.app_info->name, host.app_info->version);
Harald Welte3fb0b6f2010-05-19 19:02:52 +020097 if (print_copyright)
Harald Welte237f6242010-05-25 23:00:45 +020098 printf("\n%s\n", host.app_info->copyright);
Harald Welte3fb0b6f2010-05-19 19:02:52 +020099}
100
101/* Utility function to concatenate argv argument into a single string
102 with inserting ' ' character between each argument. */
103char *argv_concat(const char **argv, int argc, int shift)
104{
105 int i;
106 size_t len;
107 char *str;
108 char *p;
109
110 len = 0;
111 for (i = shift; i < argc; i++)
112 len += strlen(argv[i]) + 1;
113 if (!len)
114 return NULL;
115 p = str = _talloc_zero(tall_vty_cmd_ctx, len, "arvg_concat");
116 for (i = shift; i < argc; i++) {
117 size_t arglen;
118 memcpy(p, argv[i], (arglen = strlen(argv[i])));
119 p += arglen;
120 *p++ = ' ';
121 }
122 *(p - 1) = '\0';
123 return str;
124}
125
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200126/*! Install top node of command vector. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200127void install_node(struct cmd_node *node, int (*func) (struct vty *))
128{
129 vector_set_index(cmdvec, node->node, node);
130 node->func = func;
131 node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
132}
133
134/* Compare two command's string. Used in sort_node (). */
135static int cmp_node(const void *p, const void *q)
136{
137 struct cmd_element *a = *(struct cmd_element **)p;
138 struct cmd_element *b = *(struct cmd_element **)q;
139
140 return strcmp(a->string, b->string);
141}
142
143static int cmp_desc(const void *p, const void *q)
144{
145 struct desc *a = *(struct desc **)p;
146 struct desc *b = *(struct desc **)q;
147
148 return strcmp(a->cmd, b->cmd);
149}
150
Jacob Erlbeck2442e092013-09-06 16:51:58 +0200151static int is_config_child(struct vty *vty)
Holger Hans Peter Freyther50cfb782010-08-25 13:23:53 +0800152{
Holger Hans Peter Freyther8304b1e2010-09-04 11:19:39 +0800153 if (vty->node <= CONFIG_NODE)
Holger Hans Peter Freyther3e85e8d2010-08-26 14:37:10 +0800154 return 0;
Holger Hans Peter Freyther8304b1e2010-09-04 11:19:39 +0800155 else if (vty->node > CONFIG_NODE && vty->node < _LAST_OSMOVTY_NODE)
Holger Hans Peter Freyther3e85e8d2010-08-26 14:37:10 +0800156 return 1;
157 else if (host.app_info->is_config_node)
Holger Hans Peter Freyther8f09f012010-08-25 17:34:56 +0800158 return host.app_info->is_config_node(vty, vty->node);
Holger Hans Peter Freyther3e85e8d2010-08-26 14:37:10 +0800159 else
160 return vty->node > CONFIG_NODE;
Holger Hans Peter Freyther50cfb782010-08-25 13:23:53 +0800161}
162
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200163/*! Sort each node's command element according to command string. */
Harald Welte95b2b472011-07-16 11:58:09 +0200164void sort_node(void)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200165{
166 unsigned int i, j;
167 struct cmd_node *cnode;
168 vector descvec;
169 struct cmd_element *cmd_element;
170
171 for (i = 0; i < vector_active(cmdvec); i++)
172 if ((cnode = vector_slot(cmdvec, i)) != NULL) {
173 vector cmd_vector = cnode->cmd_vector;
174 qsort(cmd_vector->index, vector_active(cmd_vector),
175 sizeof(void *), cmp_node);
176
177 for (j = 0; j < vector_active(cmd_vector); j++)
178 if ((cmd_element =
179 vector_slot(cmd_vector, j)) != NULL
180 && vector_active(cmd_element->strvec)) {
181 descvec =
182 vector_slot(cmd_element->strvec,
183 vector_active
184 (cmd_element->strvec) -
185 1);
186 qsort(descvec->index,
187 vector_active(descvec),
188 sizeof(void *), cmp_desc);
189 }
190 }
191}
192
Harald Welte7acb30c2011-08-17 17:13:48 +0200193/*! Breaking up string into each command piece. I assume given
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200194 character is separated by a space character. Return value is a
195 vector which includes char ** data element. */
196vector cmd_make_strvec(const char *string)
197{
198 const char *cp, *start;
199 char *token;
200 int strlen;
201 vector strvec;
202
203 if (string == NULL)
204 return NULL;
205
206 cp = string;
207
208 /* Skip white spaces. */
209 while (isspace((int)*cp) && *cp != '\0')
210 cp++;
211
212 /* Return if there is only white spaces */
213 if (*cp == '\0')
214 return NULL;
215
216 if (*cp == '!' || *cp == '#')
217 return NULL;
218
219 /* Prepare return vector. */
220 strvec = vector_init(VECTOR_MIN_SIZE);
221
222 /* Copy each command piece and set into vector. */
223 while (1) {
224 start = cp;
225 while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') &&
226 *cp != '\0')
227 cp++;
228 strlen = cp - start;
229 token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "make_strvec");
230 memcpy(token, start, strlen);
231 *(token + strlen) = '\0';
232 vector_set(strvec, token);
233
234 while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') &&
235 *cp != '\0')
236 cp++;
237
238 if (*cp == '\0')
239 return strvec;
240 }
241}
242
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200243/*! Free allocated string vector. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200244void cmd_free_strvec(vector v)
245{
246 unsigned int i;
247 char *cp;
248
249 if (!v)
250 return;
251
252 for (i = 0; i < vector_active(v); i++)
253 if ((cp = vector_slot(v, i)) != NULL)
254 talloc_free(cp);
255
256 vector_free(v);
257}
258
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200259/*! Fetch next description. Used in \ref cmd_make_descvec(). */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200260static char *cmd_desc_str(const char **string)
261{
262 const char *cp, *start;
263 char *token;
264 int strlen;
265
266 cp = *string;
267
268 if (cp == NULL)
269 return NULL;
270
271 /* Skip white spaces. */
272 while (isspace((int)*cp) && *cp != '\0')
273 cp++;
274
275 /* Return if there is only white spaces */
276 if (*cp == '\0')
277 return NULL;
278
279 start = cp;
280
281 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
282 cp++;
283
284 strlen = cp - start;
285 token = _talloc_zero(tall_vty_cmd_ctx, strlen + 1, "cmd_desc_str");
286 memcpy(token, start, strlen);
287 *(token + strlen) = '\0';
288
289 *string = cp;
290
291 return token;
292}
293
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200294/*! New string vector. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200295static vector cmd_make_descvec(const char *string, const char *descstr)
296{
297 int multiple = 0;
298 const char *sp;
299 char *token;
300 int len;
301 const char *cp;
302 const char *dp;
303 vector allvec;
304 vector strvec = NULL;
305 struct desc *desc;
306
307 cp = string;
308 dp = descstr;
309
310 if (cp == NULL)
311 return NULL;
312
313 allvec = vector_init(VECTOR_MIN_SIZE);
314
315 while (1) {
316 while (isspace((int)*cp) && *cp != '\0')
317 cp++;
318
319 if (*cp == '(') {
320 multiple = 1;
321 cp++;
322 }
323 if (*cp == ')') {
324 multiple = 0;
325 cp++;
326 }
327 if (*cp == '|') {
Harald Weltea99d45a2015-11-12 13:48:23 +0100328 OSMO_ASSERT(multiple);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200329 cp++;
330 }
331
332 while (isspace((int)*cp) && *cp != '\0')
333 cp++;
334
335 if (*cp == '(') {
336 multiple = 1;
337 cp++;
338 }
339
340 if (*cp == '\0')
341 return allvec;
342
343 sp = cp;
344
345 while (!
346 (isspace((int)*cp) || *cp == '\r' || *cp == '\n'
347 || *cp == ')' || *cp == '|') && *cp != '\0')
348 cp++;
349
350 len = cp - sp;
351
352 token = _talloc_zero(tall_vty_cmd_ctx, len + 1, "cmd_make_descvec");
353 memcpy(token, sp, len);
354 *(token + len) = '\0';
355
356 desc = talloc_zero(tall_vty_cmd_ctx, struct desc);
357 desc->cmd = token;
358 desc->str = cmd_desc_str(&dp);
359
360 if (multiple) {
361 if (multiple == 1) {
362 strvec = vector_init(VECTOR_MIN_SIZE);
363 vector_set(allvec, strvec);
364 }
365 multiple++;
366 } else {
367 strvec = vector_init(VECTOR_MIN_SIZE);
368 vector_set(allvec, strvec);
369 }
370 vector_set(strvec, desc);
371 }
372}
373
374/* Count mandantory string vector size. This is to determine inputed
375 command has enough command length. */
376static int cmd_cmdsize(vector strvec)
377{
378 unsigned int i;
379 int size = 0;
380 vector descvec;
381 struct desc *desc;
382
383 for (i = 0; i < vector_active(strvec); i++)
384 if ((descvec = vector_slot(strvec, i)) != NULL) {
385 if ((vector_active(descvec)) == 1
386 && (desc = vector_slot(descvec, 0)) != NULL) {
387 if (desc->cmd == NULL || CMD_OPTION(desc->cmd))
388 return size;
389 else
390 size++;
391 } else
392 size++;
393 }
394 return size;
395}
396
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200397/*! Return prompt character of specified node. */
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200398const char *cmd_prompt(enum node_type node)
399{
400 struct cmd_node *cnode;
401
402 cnode = vector_slot(cmdvec, node);
403 return cnode->prompt;
404}
405
Alexander Couzensad580ba2016-05-16 16:01:45 +0200406/*!
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200407 * escape all special asciidoc symbols
Alexander Couzensad580ba2016-05-16 16:01:45 +0200408 * \param unsafe string
409 * \return a new talloc char *
410 */
411char *osmo_asciidoc_escape(const char *inp)
412{
413 int _strlen;
414 char *out, *out_ptr;
415 int len = 0, i, j;
416
417 if (!inp)
418 return NULL;
419 _strlen = strlen(inp);
420
421 for (i = 0; i < _strlen; ++i) {
422 switch (inp[i]) {
423 case '|':
424 len += 2;
425 break;
426 default:
427 len += 1;
428 break;
429 }
430 }
431
432 out = talloc_size(NULL, len + 1);
433 if (!out)
434 return NULL;
435
436 out_ptr = out;
437
438#define ADD(out, str) \
439 for (j = 0; j < strlen(str); ++j) \
440 *(out++) = str[j];
441
442 for (i = 0; i < _strlen; ++i) {
443 switch (inp[i]) {
444 case '|':
445 ADD(out_ptr, "\\|");
446 break;
447 default:
448 *(out_ptr++) = inp[i];
449 break;
450 }
451 }
452
453#undef ADD
454
455 out_ptr[0] = '\0';
456 return out;
457}
458
Holger Hans Peter Freyther8297c812011-11-18 23:14:24 +0100459static char *xml_escape(const char *inp)
460{
461 int _strlen;
462 char *out, *out_ptr;
463 int len = 0, i, j;
464
465 if (!inp)
466 return NULL;
467 _strlen = strlen(inp);
468
469 for (i = 0; i < _strlen; ++i) {
470 switch (inp[i]) {
471 case '"':
472 len += 6;
473 break;
474 case '\'':
475 len += 6;
476 break;
477 case '<':
478 len += 4;
479 break;
480 case '>':
481 len += 4;
482 break;
483 case '&':
484 len += 5;
485 break;
486 default:
487 len += 1;
488 break;
489 }
490 }
491
492 out = talloc_size(NULL, len + 1);
493 if (!out)
494 return NULL;
495
496 out_ptr = out;
497
498#define ADD(out, str) \
499 for (j = 0; j < strlen(str); ++j) \
500 *(out++) = str[j];
501
502 for (i = 0; i < _strlen; ++i) {
503 switch (inp[i]) {
504 case '"':
505 ADD(out_ptr, "&quot;");
506 break;
507 case '\'':
508 ADD(out_ptr, "&apos;");
509 break;
510 case '<':
511 ADD(out_ptr, "&lt;");
512 break;
513 case '>':
514 ADD(out_ptr, "&gt;");
515 break;
516 case '&':
517 ADD(out_ptr, "&amp;");
518 break;
519 default:
520 *(out_ptr++) = inp[i];
521 break;
522 }
523 }
524
525#undef ADD
526
527 out_ptr[0] = '\0';
528 return out;
529}
530
531/*
532 * Write one cmd_element as XML to the given VTY.
533 */
534static int vty_dump_element(struct cmd_element *cmd, struct vty *vty)
535{
536 char *xml_string = xml_escape(cmd->string);
537
538 vty_out(vty, " <command id='%s'>%s", xml_string, VTY_NEWLINE);
539 vty_out(vty, " <params>%s", VTY_NEWLINE);
540
541 int j;
542 for (j = 0; j < vector_count(cmd->strvec); ++j) {
543 vector descvec = vector_slot(cmd->strvec, j);
544 int i;
545 for (i = 0; i < vector_active(descvec); ++i) {
546 char *xml_param, *xml_doc;
547 struct desc *desc = vector_slot(descvec, i);
548 if (desc == NULL)
549 continue;
550
551 xml_param = xml_escape(desc->cmd);
552 xml_doc = xml_escape(desc->str);
553 vty_out(vty, " <param name='%s' doc='%s' />%s",
554 xml_param, xml_doc, VTY_NEWLINE);
555 talloc_free(xml_param);
556 talloc_free(xml_doc);
557 }
558 }
559
560 vty_out(vty, " </params>%s", VTY_NEWLINE);
561 vty_out(vty, " </command>%s", VTY_NEWLINE);
562
563 talloc_free(xml_string);
564 return 0;
565}
566
567/*
568 * Dump all nodes and commands associated with a given node as XML to the VTY.
569 */
570static int vty_dump_nodes(struct vty *vty)
571{
572 int i, j;
573
574 vty_out(vty, "<vtydoc xmlns='urn:osmocom:xml:libosmocore:vty:doc:1.0'>%s", VTY_NEWLINE);
575
576 for (i = 0; i < vector_active(cmdvec); ++i) {
577 struct cmd_node *cnode;
578 cnode = vector_slot(cmdvec, i);
579 if (!cnode)
580 continue;
581
582 vty_out(vty, " <node id='%d'>%s", i, VTY_NEWLINE);
583
584 for (j = 0; j < vector_active(cnode->cmd_vector); ++j) {
585 struct cmd_element *elem;
586 elem = vector_slot(cnode->cmd_vector, j);
587 vty_dump_element(elem, vty);
588 }
589
590 vty_out(vty, " </node>%s", VTY_NEWLINE);
591 }
592
593 vty_out(vty, "</vtydoc>%s", VTY_NEWLINE);
594
595 return 0;
596}
597
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200598/* Check if a command with given string exists at given node */
Harald Welteaddeaa32017-01-07 12:52:00 +0100599static int check_element_exists(struct cmd_node *cnode, const char *cmdstring)
600{
601 int i;
602
603 for (i = 0; i < vector_active(cnode->cmd_vector); ++i) {
604 struct cmd_element *elem;
605 elem = vector_slot(cnode->cmd_vector, i);
606 if (!elem->string)
607 continue;
608 if (!strcmp(elem->string, cmdstring))
609 return 1;
610 }
611 return 0;
612}
613
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200614/*! Install a command into a node
Harald Welte7acb30c2011-08-17 17:13:48 +0200615 * \param[in] ntype Node Type
616 * \param[cmd] element to be installed
617 */
Holger Hans Peter Freythera9e52522015-08-02 02:14:07 +0000618void install_element(int ntype, struct cmd_element *cmd)
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200619{
620 struct cmd_node *cnode;
621
622 cnode = vector_slot(cmdvec, ntype);
623
Harald Weltea99d45a2015-11-12 13:48:23 +0100624 OSMO_ASSERT(cnode);
Harald Welteaddeaa32017-01-07 12:52:00 +0100625 /* ensure no _identical_ command has been registered at this
626 * node so far */
627 OSMO_ASSERT(!check_element_exists(cnode, cmd->string));
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200628
629 vector_set(cnode->cmd_vector, cmd);
630
631 cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc);
632 cmd->cmdsize = cmd_cmdsize(cmd->strvec);
633}
634
635/* Install a command into VIEW and ENABLE node */
636void install_element_ve(struct cmd_element *cmd)
637{
638 install_element(VIEW_NODE, cmd);
639 install_element(ENABLE_NODE, cmd);
640}
641
642#ifdef VTY_CRYPT_PW
643static unsigned char itoa64[] =
644 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
645
646static void to64(char *s, long v, int n)
647{
648 while (--n >= 0) {
649 *s++ = itoa64[v & 0x3f];
650 v >>= 6;
651 }
652}
653
654static char *zencrypt(const char *passwd)
655{
656 char salt[6];
657 struct timeval tv;
658 char *crypt(const char *, const char *);
659
Neels Hofmeyr8e2f7e82016-09-22 03:58:13 +0200660 osmo_gettimeofday(&tv, 0);
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200661
662 to64(&salt[0], random(), 3);
663 to64(&salt[3], tv.tv_usec, 3);
664 salt[5] = '\0';
665
666 return crypt(passwd, salt);
667}
668#endif
669
670/* This function write configuration of this host. */
671static int config_write_host(struct vty *vty)
672{
673 if (host.name)
674 vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE);
675
676 if (host.encrypt) {
677 if (host.password_encrypt)
678 vty_out(vty, "password 8 %s%s", host.password_encrypt,
679 VTY_NEWLINE);
680 if (host.enable_encrypt)
681 vty_out(vty, "enable password 8 %s%s",
682 host.enable_encrypt, VTY_NEWLINE);
683 } else {
684 if (host.password)
685 vty_out(vty, "password %s%s", host.password,
686 VTY_NEWLINE);
687 if (host.enable)
688 vty_out(vty, "enable password %s%s", host.enable,
689 VTY_NEWLINE);
690 }
691
692 if (host.advanced)
693 vty_out(vty, "service advanced-vty%s", VTY_NEWLINE);
694
695 if (host.encrypt)
696 vty_out(vty, "service password-encryption%s", VTY_NEWLINE);
697
698 if (host.lines >= 0)
699 vty_out(vty, "service terminal-length %d%s", host.lines,
700 VTY_NEWLINE);
701
702 if (host.motdfile)
703 vty_out(vty, "banner motd file %s%s", host.motdfile,
704 VTY_NEWLINE);
705 else if (!host.motd)
706 vty_out(vty, "no banner motd%s", VTY_NEWLINE);
707
708 return 1;
709}
710
711/* Utility function for getting command vector. */
712static vector cmd_node_vector(vector v, enum node_type ntype)
713{
714 struct cmd_node *cnode = vector_slot(v, ntype);
715 return cnode->cmd_vector;
716}
717
718/* Completion match types. */
719enum match_type {
Sylvain Munaut4d8eea42012-12-28 11:58:23 +0100720 no_match = 0,
721 any_match,
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200722 extend_match,
723 ipv4_prefix_match,
724 ipv4_match,
725 ipv6_prefix_match,
726 ipv6_match,
727 range_match,
728 vararg_match,
729 partly_match,
Sylvain Munaut4d8eea42012-12-28 11:58:23 +0100730 exact_match,
Harald Welte3fb0b6f2010-05-19 19:02:52 +0200731};
732
733static enum match_type cmd_ipv4_match(const char *str)
734{
735 const char *sp;
736 int dots = 0, nums = 0;
737 char buf[4];
738
739 if (str == NULL)
740 return partly_match;
741
742 for (;;) {
743 memset(buf, 0, sizeof(buf));
744 sp = str;
745 while (*str != '\0') {
746 if (*str == '.') {
747 if (dots >= 3)
748 return no_match;
749
750 if (*(str + 1) == '.')
751 return no_match;
752
753 if (*(str + 1) == '\0')
754 return partly_match;
755
756 dots++;
757 break;
758 }
759 if (!isdigit((int)*str))
760 return no_match;
761
762 str++;
763 }
764
765 if (str - sp > 3)
766 return no_match;
767
768 strncpy(buf, sp, str - sp);
769 if (atoi(buf) > 255)
770 return no_match;
771
772 nums++;
773
774 if (*str == '\0')
775 break;
776
777 str++;
778 }
779
780 if (nums < 4)
781 return partly_match;
782
783 return exact_match;
784}
785
786static enum match_type cmd_ipv4_prefix_match(const char *str)
787{
788 const char *sp;
789 int dots = 0;
790 char buf[4];
791
792 if (str == NULL)
793 return partly_match;
794
795 for (;;) {
796 memset(buf, 0, sizeof(buf));
797 sp = str;
798 while (*str != '\0' && *str != '/') {
799 if (*str == '.') {
800 if (dots == 3)
801 return no_match;
802
803 if (*(str + 1) == '.' || *(str + 1) == '/')
804 return no_match;
805
806 if (*(str + 1) == '\0')
807 return partly_match;
808
809 dots++;
810 break;
811 }
812
813 if (!isdigit((int)*str))
814 return no_match;
815
816 str++;
817 }
818
819 if (str - sp > 3)
820 return no_match;
821
822 strncpy(buf, sp, str - sp);
823 if (atoi(buf) > 255)
824 return no_match;
825
826 if (dots == 3) {
827 if (*str == '/') {
828 if (*(str + 1) == '\0')
829 return partly_match;
830
831 str++;
832 break;
833 } else if (*str == '\0')
834 return partly_match;
835 }
836
837 if (*str == '\0')
838 return partly_match;
839
840 str++;
841 }
842
843 sp = str;
844 while (*str != '\0') {
845 if (!isdigit((int)*str))
846 return no_match;
847
848 str++;
849 }
850
851 if (atoi(sp) > 32)
852 return no_match;
853
854 return exact_match;
855}
856
857#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
858#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
859#define STATE_START 1
860#define STATE_COLON 2
861#define STATE_DOUBLE 3
862#define STATE_ADDR 4
863#define STATE_DOT 5
864#define STATE_SLASH 6
865#define STATE_MASK 7
866
867#ifdef HAVE_IPV6
868
869static enum match_type cmd_ipv6_match(const char *str)
870{
871 int state = STATE_START;
872 int colons = 0, nums = 0, double_colon = 0;
873 const char *sp = NULL;
874 struct sockaddr_in6 sin6_dummy;
875 int ret;
876
877 if (str == NULL)
878 return partly_match;
879
880 if (strspn(str, IPV6_ADDR_STR) != strlen(str))
881 return no_match;
882
883 /* use inet_pton that has a better support,
884 * for example inet_pton can support the automatic addresses:
885 * ::1.2.3.4
886 */
887 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
888
889 if (ret == 1)
890 return exact_match;
891
892 while (*str != '\0') {
893 switch (state) {
894 case STATE_START:
895 if (*str == ':') {
896 if (*(str + 1) != ':' && *(str + 1) != '\0')
897 return no_match;
898 colons--;
899 state = STATE_COLON;
900 } else {
901 sp = str;
902 state = STATE_ADDR;
903 }
904
905 continue;
906 case STATE_COLON:
907 colons++;
908 if (*(str + 1) == ':')
909 state = STATE_DOUBLE;
910 else {
911 sp = str + 1;
912 state = STATE_ADDR;
913 }
914 break;
915 case STATE_DOUBLE:
916 if (double_colon)
917 return no_match;
918
919 if (*(str + 1) == ':')
920 return no_match;
921 else {
922 if (*(str + 1) != '\0')
923 colons++;
924 sp = str + 1;
925 state = STATE_ADDR;
926 }
927
928 double_colon++;
929 nums++;
930 break;
931 case STATE_ADDR:
932 if (*(str + 1) == ':' || *(str + 1) == '\0') {
933 if (str - sp > 3)
934 return no_match;
935
936 nums++;
937 state = STATE_COLON;
938 }
939 if (*(str + 1) == '.')
940 state = STATE_DOT;
941 break;
942 case STATE_DOT:
943 state = STATE_ADDR;
944 break;
945 default:
946 break;
947 }
948
949 if (nums > 8)
950 return no_match;
951
952 if (colons > 7)
953 return no_match;
954
955 str++;
956 }
957
958#if 0
959 if (nums < 11)
960 return partly_match;
961#endif /* 0 */
962
963 return exact_match;
964}
965
966static enum match_type cmd_ipv6_prefix_match(const char *str)
967{
968 int state = STATE_START;
969 int colons = 0, nums = 0, double_colon = 0;
970 int mask;
971 const char *sp = NULL;
972 char *endptr = NULL;
973
974 if (str == NULL)
975 return partly_match;
976
977 if (strspn(str, IPV6_PREFIX_STR) != strlen(str))
978 return no_match;
979
980 while (*str != '\0' && state != STATE_MASK) {
981 switch (state) {
982 case STATE_START:
983 if (*str == ':') {
984 if (*(str + 1) != ':' && *(str + 1) != '\0')
985 return no_match;
986 colons--;
987 state = STATE_COLON;
988 } else {
989 sp = str;
990 state = STATE_ADDR;
991 }
992
993 continue;
994 case STATE_COLON:
995 colons++;
996 if (*(str + 1) == '/')
997 return no_match;
998 else if (*(str + 1) == ':')
999 state = STATE_DOUBLE;
1000 else {
1001 sp = str + 1;
1002 state = STATE_ADDR;
1003 }
1004 break;
1005 case STATE_DOUBLE:
1006 if (double_colon)
1007 return no_match;
1008
1009 if (*(str + 1) == ':')
1010 return no_match;
1011 else {
1012 if (*(str + 1) != '\0' && *(str + 1) != '/')
1013 colons++;
1014 sp = str + 1;
1015
1016 if (*(str + 1) == '/')
1017 state = STATE_SLASH;
1018 else
1019 state = STATE_ADDR;
1020 }
1021
1022 double_colon++;
1023 nums += 1;
1024 break;
1025 case STATE_ADDR:
1026 if (*(str + 1) == ':' || *(str + 1) == '.'
1027 || *(str + 1) == '\0' || *(str + 1) == '/') {
1028 if (str - sp > 3)
1029 return no_match;
1030
1031 for (; sp <= str; sp++)
1032 if (*sp == '/')
1033 return no_match;
1034
1035 nums++;
1036
1037 if (*(str + 1) == ':')
1038 state = STATE_COLON;
1039 else if (*(str + 1) == '.')
1040 state = STATE_DOT;
1041 else if (*(str + 1) == '/')
1042 state = STATE_SLASH;
1043 }
1044 break;
1045 case STATE_DOT:
1046 state = STATE_ADDR;
1047 break;
1048 case STATE_SLASH:
1049 if (*(str + 1) == '\0')
1050 return partly_match;
1051
1052 state = STATE_MASK;
1053 break;
1054 default:
1055 break;
1056 }
1057
1058 if (nums > 11)
1059 return no_match;
1060
1061 if (colons > 7)
1062 return no_match;
1063
1064 str++;
1065 }
1066
1067 if (state < STATE_MASK)
1068 return partly_match;
1069
1070 mask = strtol(str, &endptr, 10);
1071 if (*endptr != '\0')
1072 return no_match;
1073
1074 if (mask < 0 || mask > 128)
1075 return no_match;
1076
1077/* I don't know why mask < 13 makes command match partly.
1078 Forgive me to make this comments. I Want to set static default route
1079 because of lack of function to originate default in ospf6d; sorry
1080 yasu
1081 if (mask < 13)
1082 return partly_match;
1083*/
1084
1085 return exact_match;
1086}
1087
1088#endif /* HAVE_IPV6 */
1089
1090#define DECIMAL_STRLEN_MAX 10
1091
1092static int cmd_range_match(const char *range, const char *str)
1093{
1094 char *p;
1095 char buf[DECIMAL_STRLEN_MAX + 1];
1096 char *endptr = NULL;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001097
1098 if (str == NULL)
1099 return 1;
1100
Andreas Eversberg33f0fc32010-07-13 13:50:39 +02001101 if (range[1] == '-') {
1102 signed long min = 0, max = 0, val;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001103
Andreas Eversberg33f0fc32010-07-13 13:50:39 +02001104 val = strtol(str, &endptr, 10);
1105 if (*endptr != '\0')
1106 return 0;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001107
Andreas Eversberg33f0fc32010-07-13 13:50:39 +02001108 range += 2;
1109 p = strchr(range, '-');
1110 if (p == NULL)
1111 return 0;
1112 if (p - range > DECIMAL_STRLEN_MAX)
1113 return 0;
1114 strncpy(buf, range, p - range);
1115 buf[p - range] = '\0';
1116 min = -strtol(buf, &endptr, 10);
1117 if (*endptr != '\0')
1118 return 0;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001119
Andreas Eversberg33f0fc32010-07-13 13:50:39 +02001120 range = p + 1;
1121 p = strchr(range, '>');
1122 if (p == NULL)
1123 return 0;
1124 if (p - range > DECIMAL_STRLEN_MAX)
1125 return 0;
1126 strncpy(buf, range, p - range);
1127 buf[p - range] = '\0';
1128 max = strtol(buf, &endptr, 10);
1129 if (*endptr != '\0')
1130 return 0;
1131
1132 if (val < min || val > max)
1133 return 0;
1134 } else {
1135 unsigned long min, max, val;
1136
1137 val = strtoul(str, &endptr, 10);
1138 if (*endptr != '\0')
1139 return 0;
1140
1141 range++;
1142 p = strchr(range, '-');
1143 if (p == NULL)
1144 return 0;
1145 if (p - range > DECIMAL_STRLEN_MAX)
1146 return 0;
1147 strncpy(buf, range, p - range);
1148 buf[p - range] = '\0';
1149 min = strtoul(buf, &endptr, 10);
1150 if (*endptr != '\0')
1151 return 0;
1152
1153 range = p + 1;
1154 p = strchr(range, '>');
1155 if (p == NULL)
1156 return 0;
1157 if (p - range > DECIMAL_STRLEN_MAX)
1158 return 0;
1159 strncpy(buf, range, p - range);
1160 buf[p - range] = '\0';
1161 max = strtoul(buf, &endptr, 10);
1162 if (*endptr != '\0')
1163 return 0;
1164
1165 if (val < min || val > max)
1166 return 0;
1167 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001168
1169 return 1;
1170}
1171
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001172/* helper to retrieve the 'real' argument string from an optional argument */
1173static char *
1174cmd_deopt(const char *str)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001175{
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001176 /* we've got "[blah]". We want to strip off the []s and redo the
1177 * match check for "blah"
1178 */
1179 size_t len = strlen(str);
1180 char *tmp;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001181
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001182 if (len < 3)
1183 return NULL;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001184
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001185 /* tmp will hold a string of len-2 chars, so 'len' size is fine */
1186 tmp = talloc_size(NULL, len);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001187
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001188 memcpy(tmp, (str + 1), len - 2);
1189 tmp[len - 2] = '\0';
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001190
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001191 return tmp;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001192}
1193
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001194static enum match_type
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001195cmd_match(const char *str, const char *command,
1196 enum match_type min, bool recur)
1197{
1198
1199 if (recur && CMD_OPTION(str))
1200 {
1201 enum match_type ret;
1202 char *tmp = cmd_deopt(str);
1203
1204 /* this would be a bug in a command, however handle it gracefully
1205 * as it we only discover it if a user tries to run it
1206 */
1207 if (tmp == NULL)
1208 return no_match;
1209
1210 ret = cmd_match(tmp, command, min, false);
1211
1212 talloc_free(tmp);
1213
1214 return ret;
1215 }
1216 else if (CMD_VARARG(str))
1217 return vararg_match;
1218 else if (CMD_RANGE(str))
1219 {
1220 if (cmd_range_match(str, command))
1221 return range_match;
1222 }
1223#ifdef HAVE_IPV6
1224 else if (CMD_IPV6(str))
1225 {
1226 if (cmd_ipv6_match(command) >= min)
1227 return ipv6_match;
1228 }
1229 else if (CMD_IPV6_PREFIX(str))
1230 {
1231 if (cmd_ipv6_prefix_match(command) >= min)
1232 return ipv6_prefix_match;
1233 }
1234#endif /* HAVE_IPV6 */
1235 else if (CMD_IPV4(str))
1236 {
1237 if (cmd_ipv4_match(command) >= min)
1238 return ipv4_match;
1239 }
1240 else if (CMD_IPV4_PREFIX(str))
1241 {
1242 if (cmd_ipv4_prefix_match(command) >= min)
1243 return ipv4_prefix_match;
1244 }
1245 else if (CMD_VARIABLE(str))
1246 return extend_match;
1247 else if (strncmp(command, str, strlen(command)) == 0)
1248 {
1249 if (strcmp(command, str) == 0)
1250 return exact_match;
1251 else if (partly_match >= min)
1252 return partly_match;
1253 }
1254
1255 return no_match;
1256}
1257
1258/* Filter vector at the specified index and by the given command string, to
1259 * the desired matching level (thus allowing part matches), and return match
1260 * type flag.
1261 */
1262static enum match_type
1263cmd_filter(char *command, vector v, unsigned int index, enum match_type level)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001264{
1265 unsigned int i;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001266 struct cmd_element *cmd_element;
1267 enum match_type match_type;
1268 vector descvec;
1269 struct desc *desc;
1270
1271 match_type = no_match;
1272
1273 /* If command and cmd_element string does not match set NULL to vector */
1274 for (i = 0; i < vector_active(v); i++)
1275 if ((cmd_element = vector_slot(v, i)) != NULL) {
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001276 if (index >= vector_active(cmd_element->strvec))
1277 vector_slot(v, i) = NULL;
1278 else {
1279 unsigned int j;
1280 int matched = 0;
1281
1282 descvec =
1283 vector_slot(cmd_element->strvec, index);
1284
1285 for (j = 0; j < vector_active(descvec); j++)
1286 if ((desc = vector_slot(descvec, j))) {
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001287 enum match_type ret;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001288
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001289 ret = cmd_match (desc->cmd, command, level, true);
1290
1291 if (ret != no_match)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001292 matched++;
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001293
1294 if (match_type < ret)
1295 match_type = ret;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001296 }
1297 if (!matched)
1298 vector_slot(v, i) = NULL;
1299 }
1300 }
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001301
1302 if (match_type == no_match)
1303 return no_match;
1304
1305 /* 2nd pass: We now know the 'strongest' match type for the index, so we
1306 * go again and filter out commands whose argument (at this index) is
1307 * 'weaker'. E.g., if we have 2 commands:
1308 *
1309 * foo bar <1-255>
1310 * foo bar BLAH
1311 *
1312 * and the command string is 'foo bar 10', then we will get here with with
1313 * 'range_match' being the strongest match. However, if 'BLAH' came
1314 * earlier, it won't have been filtered out (as a CMD_VARIABLE allows "10").
1315 *
1316 * If we don't do a 2nd pass and filter it out, the higher-layers will
1317 * consider this to be ambiguous.
1318 */
1319 for (i = 0; i < vector_active(v); i++)
1320 if ((cmd_element = vector_slot(v, i)) != NULL) {
1321 if (index >= vector_active(cmd_element->strvec))
1322 vector_slot(v, i) = NULL;
1323 else {
1324 unsigned int j;
1325 int matched = 0;
1326
1327 descvec =
1328 vector_slot(cmd_element->strvec, index);
1329
1330 for (j = 0; j < vector_active(descvec); j++)
1331 if ((desc = vector_slot(descvec, j))) {
1332 enum match_type ret;
1333
1334 ret = cmd_match(desc->cmd, command, any_match, true);
1335
1336 if (ret >= match_type)
1337 matched++;
1338 }
1339 if (!matched)
1340 vector_slot(v, i) = NULL;
1341 }
1342 }
1343
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001344 return match_type;
1345}
1346
1347/* Check ambiguous match */
1348static int
1349is_cmd_ambiguous(char *command, vector v, int index, enum match_type type)
1350{
1351 unsigned int i;
1352 unsigned int j;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001353 struct cmd_element *cmd_element;
1354 const char *matched = NULL;
1355 vector descvec;
1356 struct desc *desc;
1357
1358 for (i = 0; i < vector_active(v); i++)
1359 if ((cmd_element = vector_slot(v, i)) != NULL) {
1360 int match = 0;
1361
1362 descvec = vector_slot(cmd_element->strvec, index);
1363
1364 for (j = 0; j < vector_active(descvec); j++)
1365 if ((desc = vector_slot(descvec, j))) {
1366 enum match_type ret;
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001367 const char *str = desc->cmd;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001368
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001369 if (CMD_OPTION(str))
1370 if ((str = cmd_deopt(str)) == NULL)
1371 continue;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001372
1373 switch (type) {
1374 case exact_match:
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001375 if (!(CMD_VARIABLE (str))
1376 && strcmp(command, str) == 0)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001377 match++;
1378 break;
1379 case partly_match:
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001380 if (!(CMD_VARIABLE (str))
1381 && strncmp(command, str, strlen (command)) == 0)
1382 {
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001383 if (matched
1384 && strcmp(matched,
1385 str) != 0)
1386 return 1; /* There is ambiguous match. */
1387 else
1388 matched = str;
1389 match++;
1390 }
1391 break;
1392 case range_match:
1393 if (cmd_range_match
1394 (str, command)) {
1395 if (matched
1396 && strcmp(matched,
1397 str) != 0)
1398 return 1;
1399 else
1400 matched = str;
1401 match++;
1402 }
1403 break;
1404#ifdef HAVE_IPV6
1405 case ipv6_match:
1406 if (CMD_IPV6(str))
1407 match++;
1408 break;
1409 case ipv6_prefix_match:
1410 if ((ret =
1411 cmd_ipv6_prefix_match
1412 (command)) != no_match) {
1413 if (ret == partly_match)
1414 return 2; /* There is incomplete match. */
1415
1416 match++;
1417 }
1418 break;
1419#endif /* HAVE_IPV6 */
1420 case ipv4_match:
1421 if (CMD_IPV4(str))
1422 match++;
1423 break;
1424 case ipv4_prefix_match:
1425 if ((ret =
1426 cmd_ipv4_prefix_match
1427 (command)) != no_match) {
1428 if (ret == partly_match)
1429 return 2; /* There is incomplete match. */
1430
1431 match++;
1432 }
1433 break;
1434 case extend_match:
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001435 if (CMD_VARIABLE (str))
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001436 match++;
1437 break;
1438 case no_match:
1439 default:
1440 break;
1441 }
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001442
1443 if (CMD_OPTION(desc->cmd))
1444 talloc_free((void*)str);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001445 }
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. */
Harald Welte80d30fe2013-02-12 11:08:57 +01001598 for (i = 0; i < index; i++) {
1599 command = vector_slot(vline, i);
1600 if (!command)
1601 continue;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001602
Harald Welte80d30fe2013-02-12 11:08:57 +01001603 match = cmd_filter(command, cmd_vector, i, any_match);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001604
Harald Welte80d30fe2013-02-12 11:08:57 +01001605 if (match == vararg_match) {
1606 struct cmd_element *cmd_element;
1607 vector descvec;
1608 unsigned int j, k;
1609
1610 for (j = 0; j < vector_active(cmd_vector); j++)
1611 if ((cmd_element =
1612 vector_slot(cmd_vector, j)) != NULL
1613 &&
1614 (vector_active(cmd_element->strvec))) {
1615 descvec =
1616 vector_slot(cmd_element->
1617 strvec,
1618 vector_active
1619 (cmd_element->
1620 strvec) - 1);
1621 for (k = 0;
1622 k < vector_active(descvec);
1623 k++) {
1624 struct desc *desc =
1625 vector_slot(descvec,
1626 k);
1627 vector_set(matchvec,
1628 desc);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001629 }
Harald Welte80d30fe2013-02-12 11:08:57 +01001630 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001631
Harald Welte80d30fe2013-02-12 11:08:57 +01001632 vector_set(matchvec, &desc_cr);
1633 vector_free(cmd_vector);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001634
Harald Welte80d30fe2013-02-12 11:08:57 +01001635 return matchvec;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001636 }
1637
Harald Welte80d30fe2013-02-12 11:08:57 +01001638 if ((ret = is_cmd_ambiguous(command, cmd_vector, i,
1639 match)) == 1) {
1640 vector_free(cmd_vector);
Holger Hans Peter Freyther047213b2013-07-03 09:32:37 +02001641 vector_free(matchvec);
Harald Welte80d30fe2013-02-12 11:08:57 +01001642 *status = CMD_ERR_AMBIGUOUS;
1643 return NULL;
1644 } else if (ret == 2) {
1645 vector_free(cmd_vector);
Holger Hans Peter Freyther047213b2013-07-03 09:32:37 +02001646 vector_free(matchvec);
Harald Welte80d30fe2013-02-12 11:08:57 +01001647 *status = CMD_ERR_NO_MATCH;
1648 return NULL;
1649 }
1650 }
1651
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001652 /* Prepare match vector */
1653 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1654
1655 /* Make sure that cmd_vector is filtered based on current word */
1656 command = vector_slot(vline, index);
1657 if (command)
Vadim Yanitskiy49a0dec2017-06-12 03:49:38 +07001658 cmd_filter(command, cmd_vector, index, any_match);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001659
1660 /* Make description vector. */
Harald Welte80d30fe2013-02-12 11:08:57 +01001661 for (i = 0; i < vector_active(cmd_vector); i++) {
1662 const char *string = NULL;
1663 vector strvec;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001664
Harald Welte80d30fe2013-02-12 11:08:57 +01001665 cmd_element = vector_slot(cmd_vector, i);
1666 if (!cmd_element)
1667 continue;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001668
Harald Welted17aa592013-02-12 11:11:34 +01001669 if (cmd_element->attr & (CMD_ATTR_DEPRECATED|CMD_ATTR_HIDDEN))
1670 continue;
1671
Harald Welte80d30fe2013-02-12 11:08:57 +01001672 strvec = cmd_element->strvec;
1673
1674 /* if command is NULL, index may be equal to vector_active */
1675 if (command && index >= vector_active(strvec))
1676 vector_slot(cmd_vector, i) = NULL;
1677 else {
1678 /* Check if command is completed. */
1679 if (command == NULL
1680 && index == vector_active(strvec)) {
1681 string = "<cr>";
1682 if (!desc_unique_string(matchvec, string))
1683 vector_set(matchvec, &desc_cr);
1684 } else {
1685 unsigned int j;
1686 vector descvec = vector_slot(strvec, index);
1687 struct desc *desc;
1688
1689 for (j = 0; j < vector_active(descvec); j++) {
1690 desc = vector_slot(descvec, j);
1691 if (!desc)
1692 continue;
1693 string = cmd_entry_function_desc
1694 (command, desc->cmd);
1695 if (!string)
1696 continue;
1697 /* Uniqueness check */
1698 if (!desc_unique_string(matchvec, string))
1699 vector_set(matchvec, desc);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001700 }
1701 }
1702 }
Harald Welte80d30fe2013-02-12 11:08:57 +01001703 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001704 vector_free(cmd_vector);
1705
1706 if (vector_slot(matchvec, 0) == NULL) {
1707 vector_free(matchvec);
1708 *status = CMD_ERR_NO_MATCH;
1709 } else
1710 *status = CMD_SUCCESS;
1711
1712 return matchvec;
1713}
1714
1715vector cmd_describe_command(vector vline, struct vty * vty, int *status)
1716{
1717 vector ret;
1718
1719 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1720 enum node_type onode;
1721 vector shifted_vline;
1722 unsigned int index;
1723
1724 onode = vty->node;
1725 vty->node = ENABLE_NODE;
1726 /* We can try it on enable node, cos' the vty is authenticated */
1727
1728 shifted_vline = vector_init(vector_count(vline));
1729 /* use memcpy? */
1730 for (index = 1; index < vector_active(vline); index++) {
1731 vector_set_index(shifted_vline, index - 1,
1732 vector_lookup(vline, index));
1733 }
1734
1735 ret = cmd_describe_command_real(shifted_vline, vty, status);
1736
1737 vector_free(shifted_vline);
1738 vty->node = onode;
1739 return ret;
1740 }
1741
1742 return cmd_describe_command_real(vline, vty, status);
1743}
1744
1745/* Check LCD of matched command. */
1746static int cmd_lcd(char **matched)
1747{
1748 int i;
1749 int j;
1750 int lcd = -1;
1751 char *s1, *s2;
1752 char c1, c2;
1753
1754 if (matched[0] == NULL || matched[1] == NULL)
1755 return 0;
1756
1757 for (i = 1; matched[i] != NULL; i++) {
1758 s1 = matched[i - 1];
1759 s2 = matched[i];
1760
1761 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1762 if (c1 != c2)
1763 break;
1764
1765 if (lcd < 0)
1766 lcd = j;
1767 else {
1768 if (lcd > j)
1769 lcd = j;
1770 }
1771 }
1772 return lcd;
1773}
1774
1775/* Command line completion support. */
1776static char **cmd_complete_command_real(vector vline, struct vty *vty,
1777 int *status)
1778{
1779 unsigned int i;
1780 vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
1781#define INIT_MATCHVEC_SIZE 10
1782 vector matchvec;
1783 struct cmd_element *cmd_element;
1784 unsigned int index;
1785 char **match_str;
1786 struct desc *desc;
1787 vector descvec;
1788 char *command;
1789 int lcd;
1790
1791 if (vector_active(vline) == 0) {
1792 *status = CMD_ERR_NO_MATCH;
Holger Hans Peter Freyther047213b2013-07-03 09:32:37 +02001793 vector_free(cmd_vector);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001794 return NULL;
1795 } else
1796 index = vector_active(vline) - 1;
1797
1798 /* First, filter by preceeding command string */
1799 for (i = 0; i < index; i++)
1800 if ((command = vector_slot(vline, i))) {
1801 enum match_type match;
1802 int ret;
1803
1804 /* First try completion match, if there is exactly match return 1 */
1805 match =
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01001806 cmd_filter(command, cmd_vector, i, any_match);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001807
1808 /* If there is exact match then filter ambiguous match else check
1809 ambiguousness. */
1810 if ((ret =
1811 is_cmd_ambiguous(command, cmd_vector, i,
1812 match)) == 1) {
1813 vector_free(cmd_vector);
1814 *status = CMD_ERR_AMBIGUOUS;
1815 return NULL;
1816 }
1817 /*
1818 else if (ret == 2)
1819 {
1820 vector_free (cmd_vector);
1821 *status = CMD_ERR_NO_MATCH;
1822 return NULL;
1823 }
1824 */
1825 }
1826
1827 /* Prepare match vector. */
1828 matchvec = vector_init(INIT_MATCHVEC_SIZE);
1829
1830 /* Now we got into completion */
1831 for (i = 0; i < vector_active(cmd_vector); i++)
1832 if ((cmd_element = vector_slot(cmd_vector, i))) {
1833 const char *string;
1834 vector strvec = cmd_element->strvec;
1835
1836 /* Check field length */
1837 if (index >= vector_active(strvec))
1838 vector_slot(cmd_vector, i) = NULL;
1839 else {
1840 unsigned int j;
1841
1842 descvec = vector_slot(strvec, index);
1843 for (j = 0; j < vector_active(descvec); j++)
1844 if ((desc = vector_slot(descvec, j))) {
1845 if ((string = cmd_entry_function(vector_slot(vline, index), desc->cmd)))
1846 if (cmd_unique_string (matchvec, string))
1847 vector_set (matchvec, talloc_strdup(tall_vty_cmd_ctx, string));
1848 }
1849 }
1850 }
1851
1852 /* We don't need cmd_vector any more. */
1853 vector_free(cmd_vector);
1854
1855 /* No matched command */
1856 if (vector_slot(matchvec, 0) == NULL) {
1857 vector_free(matchvec);
1858
1859 /* In case of 'command \t' pattern. Do you need '?' command at
1860 the end of the line. */
1861 if (vector_slot(vline, index) == '\0')
1862 *status = CMD_ERR_NOTHING_TODO;
1863 else
1864 *status = CMD_ERR_NO_MATCH;
1865 return NULL;
1866 }
1867
1868 /* Only one matched */
1869 if (vector_slot(matchvec, 1) == NULL) {
1870 match_str = (char **)matchvec->index;
1871 vector_only_wrapper_free(matchvec);
1872 *status = CMD_COMPLETE_FULL_MATCH;
1873 return match_str;
1874 }
1875 /* Make it sure last element is NULL. */
1876 vector_set(matchvec, NULL);
1877
1878 /* Check LCD of matched strings. */
1879 if (vector_slot(vline, index) != NULL) {
1880 lcd = cmd_lcd((char **)matchvec->index);
1881
1882 if (lcd) {
1883 int len = strlen(vector_slot(vline, index));
1884
1885 if (len < lcd) {
1886 char *lcdstr;
1887
1888 lcdstr = _talloc_zero(tall_vty_cmd_ctx, lcd + 1,
1889 "complete-lcdstr");
1890 memcpy(lcdstr, matchvec->index[0], lcd);
1891 lcdstr[lcd] = '\0';
1892
1893 /* match_str = (char **) &lcdstr; */
1894
1895 /* Free matchvec. */
1896 for (i = 0; i < vector_active(matchvec); i++) {
1897 if (vector_slot(matchvec, i))
1898 talloc_free(vector_slot(matchvec, i));
1899 }
1900 vector_free(matchvec);
1901
1902 /* Make new matchvec. */
1903 matchvec = vector_init(INIT_MATCHVEC_SIZE);
1904 vector_set(matchvec, lcdstr);
1905 match_str = (char **)matchvec->index;
1906 vector_only_wrapper_free(matchvec);
1907
1908 *status = CMD_COMPLETE_MATCH;
1909 return match_str;
1910 }
1911 }
1912 }
1913
1914 match_str = (char **)matchvec->index;
1915 vector_only_wrapper_free(matchvec);
1916 *status = CMD_COMPLETE_LIST_MATCH;
1917 return match_str;
1918}
1919
1920char **cmd_complete_command(vector vline, struct vty *vty, int *status)
1921{
1922 char **ret;
1923
1924 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
1925 enum node_type onode;
1926 vector shifted_vline;
1927 unsigned int index;
1928
1929 onode = vty->node;
1930 vty->node = ENABLE_NODE;
1931 /* We can try it on enable node, cos' the vty is authenticated */
1932
1933 shifted_vline = vector_init(vector_count(vline));
1934 /* use memcpy? */
1935 for (index = 1; index < vector_active(vline); index++) {
1936 vector_set_index(shifted_vline, index - 1,
1937 vector_lookup(vline, index));
1938 }
1939
1940 ret = cmd_complete_command_real(shifted_vline, vty, status);
1941
1942 vector_free(shifted_vline);
1943 vty->node = onode;
1944 return ret;
1945 }
1946
1947 return cmd_complete_command_real(vline, vty, status);
1948}
1949
1950/* return parent node */
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02001951/*
1952 * This function MUST eventually converge on a node when called repeatedly,
1953 * there must not be any cycles.
1954 * All 'config' nodes shall converge on CONFIG_NODE.
1955 * All other 'enable' nodes shall converge on ENABLE_NODE.
1956 * All 'view' only nodes shall converge on VIEW_NODE.
1957 * All other nodes shall converge on themselves or it must be ensured,
1958 * that the user's rights are not extended anyhow by calling this function.
1959 *
1960 * Note that these requirements also apply to all functions that are used
1961 * as go_parent_cb.
1962 * Note also that this function relies on the is_config_child callback to
1963 * recognize non-config nodes if go_parent_cb is not set.
1964 */
Holger Hans Peter Freythera9e52522015-08-02 02:14:07 +00001965int vty_go_parent(struct vty *vty)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001966{
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02001967 switch (vty->node) {
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02001968 case AUTH_NODE:
1969 case VIEW_NODE:
1970 case ENABLE_NODE:
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02001971 case CONFIG_NODE:
1972 break;
1973
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02001974 case AUTH_ENABLE_NODE:
1975 vty->node = VIEW_NODE;
1976 break;
1977
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02001978 case CFG_LOG_NODE:
1979 case VTY_NODE:
1980 vty->node = CONFIG_NODE;
1981 break;
1982
1983 default:
1984 if (host.app_info->go_parent_cb)
1985 host.app_info->go_parent_cb(vty);
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02001986 else if (is_config_child(vty))
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02001987 vty->node = CONFIG_NODE;
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02001988 else
1989 vty->node = VIEW_NODE;
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02001990 break;
1991 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +02001992
1993 return vty->node;
1994}
1995
1996/* Execute command by argument vline vector. */
1997static int
1998cmd_execute_command_real(vector vline, struct vty *vty,
1999 struct cmd_element **cmd)
2000{
2001 unsigned int i;
2002 unsigned int index;
2003 vector cmd_vector;
2004 struct cmd_element *cmd_element;
2005 struct cmd_element *matched_element;
2006 unsigned int matched_count, incomplete_count;
2007 int argc;
2008 const char *argv[CMD_ARGC_MAX];
2009 enum match_type match = 0;
2010 int varflag;
2011 char *command;
2012
2013 /* Make copy of command elements. */
2014 cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
2015
2016 for (index = 0; index < vector_active(vline); index++)
2017 if ((command = vector_slot(vline, index))) {
2018 int ret;
2019
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01002020 match = cmd_filter(command, cmd_vector, index,
2021 any_match);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002022
2023 if (match == vararg_match)
2024 break;
2025
2026 ret =
2027 is_cmd_ambiguous(command, cmd_vector, index, match);
2028
2029 if (ret == 1) {
2030 vector_free(cmd_vector);
2031 return CMD_ERR_AMBIGUOUS;
2032 } else if (ret == 2) {
2033 vector_free(cmd_vector);
2034 return CMD_ERR_NO_MATCH;
2035 }
2036 }
2037
2038 /* Check matched count. */
2039 matched_element = NULL;
2040 matched_count = 0;
2041 incomplete_count = 0;
2042
2043 for (i = 0; i < vector_active(cmd_vector); i++)
2044 if ((cmd_element = vector_slot(cmd_vector, i))) {
2045 if (match == vararg_match
2046 || index >= cmd_element->cmdsize) {
2047 matched_element = cmd_element;
2048#if 0
2049 printf("DEBUG: %s\n", cmd_element->string);
2050#endif
2051 matched_count++;
2052 } else {
2053 incomplete_count++;
2054 }
2055 }
2056
2057 /* Finish of using cmd_vector. */
2058 vector_free(cmd_vector);
2059
2060 /* To execute command, matched_count must be 1. */
2061 if (matched_count == 0) {
2062 if (incomplete_count)
2063 return CMD_ERR_INCOMPLETE;
2064 else
2065 return CMD_ERR_NO_MATCH;
2066 }
2067
2068 if (matched_count > 1)
2069 return CMD_ERR_AMBIGUOUS;
2070
2071 /* Argument treatment */
2072 varflag = 0;
2073 argc = 0;
2074
2075 for (i = 0; i < vector_active(vline); i++) {
2076 if (varflag)
2077 argv[argc++] = vector_slot(vline, i);
2078 else {
2079 vector descvec =
2080 vector_slot(matched_element->strvec, i);
2081
2082 if (vector_active(descvec) == 1) {
2083 struct desc *desc = vector_slot(descvec, 0);
2084
2085 if (CMD_VARARG(desc->cmd))
2086 varflag = 1;
2087
2088 if (varflag || CMD_VARIABLE(desc->cmd)
2089 || CMD_OPTION(desc->cmd))
2090 argv[argc++] = vector_slot(vline, i);
2091 } else
2092 argv[argc++] = vector_slot(vline, i);
2093 }
2094
2095 if (argc >= CMD_ARGC_MAX)
2096 return CMD_ERR_EXEED_ARGC_MAX;
2097 }
2098
2099 /* For vtysh execution. */
2100 if (cmd)
2101 *cmd = matched_element;
2102
2103 if (matched_element->daemon)
2104 return CMD_SUCCESS_DAEMON;
2105
2106 /* Execute matched command. */
2107 return (*matched_element->func) (matched_element, vty, argc, argv);
2108}
2109
2110int
2111cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd,
2112 int vtysh)
2113{
2114 int ret, saved_ret, tried = 0;
2115 enum node_type onode;
2116 void *oindex;
2117
2118 onode = vty->node;
2119 oindex = vty->index;
2120
2121 if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
2122 vector shifted_vline;
2123 unsigned int index;
2124
2125 vty->node = ENABLE_NODE;
2126 /* We can try it on enable node, cos' the vty is authenticated */
2127
2128 shifted_vline = vector_init(vector_count(vline));
2129 /* use memcpy? */
2130 for (index = 1; index < vector_active(vline); index++) {
2131 vector_set_index(shifted_vline, index - 1,
2132 vector_lookup(vline, index));
2133 }
2134
2135 ret = cmd_execute_command_real(shifted_vline, vty, cmd);
2136
2137 vector_free(shifted_vline);
2138 vty->node = onode;
2139 return ret;
2140 }
2141
2142 saved_ret = ret = cmd_execute_command_real(vline, vty, cmd);
2143
2144 if (vtysh)
2145 return saved_ret;
2146
Holger Hans Peter Freyther50cfb782010-08-25 13:23:53 +08002147 /* Go to parent for config nodes to attempt to find the right command */
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002148 while (ret != CMD_SUCCESS && ret != CMD_WARNING
Jacob Erlbeck2442e092013-09-06 16:51:58 +02002149 && is_config_child(vty)) {
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002150 vty_go_parent(vty);
2151 ret = cmd_execute_command_real(vline, vty, cmd);
2152 tried = 1;
2153 if (ret == CMD_SUCCESS || ret == CMD_WARNING) {
2154 /* succesfull command, leave the node as is */
2155 return ret;
2156 }
2157 }
2158 /* no command succeeded, reset the vty to the original node and
2159 return the error for this node */
2160 if (tried) {
2161 vty->node = onode;
2162 vty->index = oindex;
2163 }
2164 return saved_ret;
2165}
2166
2167/* Execute command by argument readline. */
2168int
2169cmd_execute_command_strict(vector vline, struct vty *vty,
2170 struct cmd_element **cmd)
2171{
2172 unsigned int i;
2173 unsigned int index;
2174 vector cmd_vector;
2175 struct cmd_element *cmd_element;
2176 struct cmd_element *matched_element;
2177 unsigned int matched_count, incomplete_count;
2178 int argc;
2179 const char *argv[CMD_ARGC_MAX];
2180 int varflag;
2181 enum match_type match = 0;
2182 char *command;
2183
2184 /* Make copy of command element */
2185 cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
2186
2187 for (index = 0; index < vector_active(vline); index++)
2188 if ((command = vector_slot(vline, index))) {
2189 int ret;
2190
Sylvain Munaut4d8eea42012-12-28 11:58:23 +01002191 match = cmd_filter(vector_slot(vline, index),
2192 cmd_vector, index, exact_match);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002193
2194 /* If command meets '.VARARG' then finish matching. */
2195 if (match == vararg_match)
2196 break;
2197
2198 ret =
2199 is_cmd_ambiguous(command, cmd_vector, index, match);
2200 if (ret == 1) {
2201 vector_free(cmd_vector);
2202 return CMD_ERR_AMBIGUOUS;
2203 }
2204 if (ret == 2) {
2205 vector_free(cmd_vector);
2206 return CMD_ERR_NO_MATCH;
2207 }
2208 }
2209
2210 /* Check matched count. */
2211 matched_element = NULL;
2212 matched_count = 0;
2213 incomplete_count = 0;
2214 for (i = 0; i < vector_active(cmd_vector); i++)
2215 if (vector_slot(cmd_vector, i) != NULL) {
2216 cmd_element = vector_slot(cmd_vector, i);
2217
2218 if (match == vararg_match
2219 || index >= cmd_element->cmdsize) {
2220 matched_element = cmd_element;
2221 matched_count++;
2222 } else
2223 incomplete_count++;
2224 }
2225
2226 /* Finish of using cmd_vector. */
2227 vector_free(cmd_vector);
2228
2229 /* To execute command, matched_count must be 1. */
2230 if (matched_count == 0) {
2231 if (incomplete_count)
2232 return CMD_ERR_INCOMPLETE;
2233 else
2234 return CMD_ERR_NO_MATCH;
2235 }
2236
2237 if (matched_count > 1)
2238 return CMD_ERR_AMBIGUOUS;
2239
2240 /* Argument treatment */
2241 varflag = 0;
2242 argc = 0;
2243
2244 for (i = 0; i < vector_active(vline); i++) {
2245 if (varflag)
2246 argv[argc++] = vector_slot(vline, i);
2247 else {
2248 vector descvec =
2249 vector_slot(matched_element->strvec, i);
2250
2251 if (vector_active(descvec) == 1) {
2252 struct desc *desc = vector_slot(descvec, 0);
2253
2254 if (CMD_VARARG(desc->cmd))
2255 varflag = 1;
2256
2257 if (varflag || CMD_VARIABLE(desc->cmd)
2258 || CMD_OPTION(desc->cmd))
2259 argv[argc++] = vector_slot(vline, i);
2260 } else
2261 argv[argc++] = vector_slot(vline, i);
2262 }
2263
2264 if (argc >= CMD_ARGC_MAX)
2265 return CMD_ERR_EXEED_ARGC_MAX;
2266 }
2267
2268 /* For vtysh execution. */
2269 if (cmd)
2270 *cmd = matched_element;
2271
2272 if (matched_element->daemon)
2273 return CMD_SUCCESS_DAEMON;
2274
2275 /* Now execute matched command */
2276 return (*matched_element->func) (matched_element, vty, argc, argv);
2277}
2278
2279/* Configration make from file. */
2280int config_from_file(struct vty *vty, FILE * fp)
2281{
2282 int ret;
2283 vector vline;
2284
2285 while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
2286 vline = cmd_make_strvec(vty->buf);
2287
2288 /* In case of comment line */
2289 if (vline == NULL)
2290 continue;
2291 /* Execute configuration command : this is strict match */
2292 ret = cmd_execute_command_strict(vline, vty, NULL);
2293
2294 /* Try again with setting node to CONFIG_NODE */
2295 while (ret != CMD_SUCCESS && ret != CMD_WARNING
2296 && ret != CMD_ERR_NOTHING_TODO
Jacob Erlbeck2442e092013-09-06 16:51:58 +02002297 && is_config_child(vty)) {
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002298 vty_go_parent(vty);
2299 ret = cmd_execute_command_strict(vline, vty, NULL);
2300 }
2301
2302 cmd_free_strvec(vline);
2303
2304 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2305 && ret != CMD_ERR_NOTHING_TODO)
2306 return ret;
2307 }
2308 return CMD_SUCCESS;
2309}
2310
2311/* Configration from terminal */
2312DEFUN(config_terminal,
2313 config_terminal_cmd,
2314 "configure terminal",
2315 "Configuration from vty interface\n" "Configuration terminal\n")
2316{
2317 if (vty_config_lock(vty))
2318 vty->node = CONFIG_NODE;
2319 else {
2320 vty_out(vty, "VTY configuration is locked by other VTY%s",
2321 VTY_NEWLINE);
2322 return CMD_WARNING;
2323 }
2324 return CMD_SUCCESS;
2325}
2326
2327/* Enable command */
2328DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n")
2329{
2330 /* If enable password is NULL, change to ENABLE_NODE */
2331 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2332 vty->type == VTY_SHELL_SERV)
2333 vty->node = ENABLE_NODE;
2334 else
2335 vty->node = AUTH_ENABLE_NODE;
2336
2337 return CMD_SUCCESS;
2338}
2339
2340/* Disable command */
2341DEFUN(disable,
2342 config_disable_cmd, "disable", "Turn off privileged mode command\n")
2343{
2344 if (vty->node == ENABLE_NODE)
2345 vty->node = VIEW_NODE;
2346 return CMD_SUCCESS;
2347}
2348
2349/* Down vty node level. */
2350gDEFUN(config_exit,
2351 config_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
2352{
2353 switch (vty->node) {
Jacob Erlbeckb3657e12013-09-10 14:04:54 +02002354 case AUTH_NODE:
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002355 case VIEW_NODE:
2356 case ENABLE_NODE:
Harald Weltea99d45a2015-11-12 13:48:23 +01002357 vty->status = VTY_CLOSE;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002358 break;
2359 case CONFIG_NODE:
2360 vty->node = ENABLE_NODE;
2361 vty_config_unlock(vty);
2362 break;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002363 default:
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02002364 if (vty->node > CONFIG_NODE)
2365 vty_go_parent (vty);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002366 break;
2367 }
2368 return CMD_SUCCESS;
2369}
2370
2371/* End of configuration. */
2372 gDEFUN(config_end,
2373 config_end_cmd, "end", "End current mode and change to enable mode.")
2374{
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02002375 if (vty->node > ENABLE_NODE) {
Jacob Erlbeck23497212013-09-10 09:07:31 +02002376 int last_node = CONFIG_NODE;
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02002377
2378 /* Repeatedly call go_parent until a top node is reached. */
2379 while (vty->node > CONFIG_NODE) {
2380 if (vty->node == last_node) {
2381 /* Ensure termination, this shouldn't happen. */
2382 break;
2383 }
2384 last_node = vty->node;
2385 vty_go_parent(vty);
2386 }
2387
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002388 vty_config_unlock(vty);
Jacob Erlbeck7eed0532013-09-06 16:51:59 +02002389 if (vty->node > ENABLE_NODE)
2390 vty->node = ENABLE_NODE;
2391 vty->index = NULL;
2392 vty->index_sub = NULL;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002393 }
2394 return CMD_SUCCESS;
2395}
2396
2397/* Show version. */
2398DEFUN(show_version,
2399 show_version_cmd, "show version", SHOW_STR "Displays program version\n")
2400{
Harald Welte237f6242010-05-25 23:00:45 +02002401 vty_out(vty, "%s %s (%s).%s", host.app_info->name,
2402 host.app_info->version,
2403 host.app_info->name ? host.app_info->name : "", VTY_NEWLINE);
2404 vty_out(vty, "%s%s", host.app_info->copyright, VTY_NEWLINE);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002405
2406 return CMD_SUCCESS;
2407}
2408
Holger Hans Peter Freyther8297c812011-11-18 23:14:24 +01002409DEFUN(show_online_help,
2410 show_online_help_cmd, "show online-help", SHOW_STR "Online help\n")
2411{
2412 vty_dump_nodes(vty);
2413 return CMD_SUCCESS;
2414}
2415
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002416/* Help display function for all node. */
2417gDEFUN(config_help,
2418 config_help_cmd, "help", "Description of the interactive help system\n")
2419{
2420 vty_out(vty,
2421 "This VTY provides advanced help features. When you need help,%s\
2422anytime at the command line please press '?'.%s\
2423%s\
2424If nothing matches, the help list will be empty and you must backup%s\
2425 until entering a '?' shows the available options.%s\
2426Two styles of help are provided:%s\
24271. Full help is available when you are ready to enter a%s\
2428command argument (e.g. 'show ?') and describes each possible%s\
2429argument.%s\
24302. Partial help is provided when an abbreviated argument is entered%s\
2431 and you want to know what arguments match the input%s\
2432 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2433 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2434 return CMD_SUCCESS;
2435}
2436
2437/* Help display function for all node. */
2438gDEFUN(config_list, config_list_cmd, "list", "Print command list\n")
2439{
2440 unsigned int i;
2441 struct cmd_node *cnode = vector_slot(cmdvec, vty->node);
2442 struct cmd_element *cmd;
2443
2444 for (i = 0; i < vector_active(cnode->cmd_vector); i++)
2445 if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL
2446 && !(cmd->attr == CMD_ATTR_DEPRECATED
2447 || cmd->attr == CMD_ATTR_HIDDEN))
2448 vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE);
2449 return CMD_SUCCESS;
2450}
2451
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002452static int write_config_file(const char *config_file, char **outpath)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002453{
2454 unsigned int i;
2455 int fd;
2456 struct cmd_node *node;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002457 char *config_file_tmp = NULL;
2458 char *config_file_sav = NULL;
2459 struct vty *file_vty;
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002460 struct stat st;
2461
2462 *outpath = NULL;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002463
2464 /* Check and see if we are operating under vtysh configuration */
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002465 config_file_sav =
2466 _talloc_zero(tall_vty_cmd_ctx,
2467 strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1,
2468 "config_file_sav");
2469 strcpy(config_file_sav, config_file);
2470 strcat(config_file_sav, CONF_BACKUP_EXT);
2471
2472 config_file_tmp = _talloc_zero(tall_vty_cmd_ctx, strlen(config_file) + 8,
2473 "config_file_tmp");
2474 sprintf(config_file_tmp, "%s.XXXXXX", config_file);
2475
2476 /* Open file to configuration write. */
2477 fd = mkstemp(config_file_tmp);
2478 if (fd < 0) {
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002479 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_tmp);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002480 talloc_free(config_file_tmp);
2481 talloc_free(config_file_sav);
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002482 return -1;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002483 }
2484
2485 /* Make vty for configuration file. */
2486 file_vty = vty_new();
2487 file_vty->fd = fd;
2488 file_vty->type = VTY_FILE;
2489
2490 /* Config file header print. */
2491 vty_out(file_vty, "!\n! %s (%s) configuration saved from vty\n!",
Harald Welte237f6242010-05-25 23:00:45 +02002492 host.app_info->name, host.app_info->version);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002493 //vty_time_print (file_vty, 1);
2494 vty_out(file_vty, "!\n");
2495
2496 for (i = 0; i < vector_active(cmdvec); i++)
2497 if ((node = vector_slot(cmdvec, i)) && node->func) {
2498 if ((*node->func) (file_vty))
2499 vty_out(file_vty, "!\n");
2500 }
2501 vty_close(file_vty);
2502
2503 if (unlink(config_file_sav) != 0)
2504 if (errno != ENOENT) {
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002505 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_sav);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002506 talloc_free(config_file_sav);
2507 talloc_free(config_file_tmp);
2508 unlink(config_file_tmp);
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002509 return -2;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002510 }
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002511
2512 /* Only link the .sav file if the original file exists */
2513 if (stat(config_file, &st) == 0) {
2514 if (link(config_file, config_file_sav) != 0) {
2515 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file_sav);
2516 talloc_free(config_file_sav);
2517 talloc_free(config_file_tmp);
2518 unlink(config_file_tmp);
2519 return -3;
2520 }
2521 sync();
2522 if (unlink(config_file) != 0) {
2523 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file);
2524 talloc_free(config_file_sav);
2525 talloc_free(config_file_tmp);
2526 unlink(config_file_tmp);
2527 return -4;
2528 }
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002529 }
2530 if (link(config_file_tmp, config_file) != 0) {
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002531 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002532 talloc_free(config_file_sav);
2533 talloc_free(config_file_tmp);
2534 unlink(config_file_tmp);
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002535 return -5;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002536 }
2537 unlink(config_file_tmp);
2538 sync();
2539
2540 talloc_free(config_file_sav);
2541 talloc_free(config_file_tmp);
2542
2543 if (chmod(config_file, 0666 & ~CONFIGFILE_MASK) != 0) {
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002544 *outpath = talloc_strdup(tall_vty_cmd_ctx, config_file);
2545 return -6;
2546 }
2547
2548 return 0;
2549}
2550
2551
2552/* Write current configuration into file. */
2553DEFUN(config_write_file,
2554 config_write_file_cmd,
2555 "write file",
2556 "Write running configuration to memory, network, or terminal\n"
2557 "Write to configuration file\n")
2558{
2559 char *failed_file;
2560 int rc;
2561
Holger Hans Peter Freyther9f0f9782014-11-21 10:40:07 +01002562 if (host.app_info->config_is_consistent) {
2563 rc = host.app_info->config_is_consistent(vty);
2564 if (!rc) {
2565 vty_out(vty, "Configuration is not consistent%s",
2566 VTY_NEWLINE);
2567 return CMD_WARNING;
2568 }
2569 }
2570
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002571 if (host.config == NULL) {
2572 vty_out(vty, "Can't save to configuration file, using vtysh.%s",
2573 VTY_NEWLINE);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002574 return CMD_WARNING;
2575 }
2576
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01002577 rc = write_config_file(host.config, &failed_file);
2578 switch (rc) {
2579 case -1:
2580 vty_out(vty, "Can't open configuration file %s.%s",
2581 failed_file, VTY_NEWLINE);
2582 rc = CMD_WARNING;
2583 break;
2584 case -2:
2585 vty_out(vty, "Can't unlink backup configuration file %s.%s",
2586 failed_file, VTY_NEWLINE);
2587 rc = CMD_WARNING;
2588 break;
2589 case -3:
2590 vty_out(vty, "Can't backup old configuration file %s.%s",
2591 failed_file, VTY_NEWLINE);
2592 rc = CMD_WARNING;
2593 break;
2594 case -4:
2595 vty_out(vty, "Can't unlink configuration file %s.%s",
2596 failed_file, VTY_NEWLINE);
2597 rc = CMD_WARNING;
2598 break;
2599 case -5:
2600 vty_out(vty, "Can't save configuration file %s.%s", failed_file,
2601 VTY_NEWLINE);
2602 rc = CMD_WARNING;
2603 break;
2604 case -6:
2605 vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
2606 failed_file, strerror(errno), errno, VTY_NEWLINE);
2607 rc = CMD_WARNING;
2608 break;
2609 default:
2610 vty_out(vty, "Configuration saved to %s%s", host.config, VTY_NEWLINE);
2611 rc = CMD_SUCCESS;
2612 break;
2613 }
2614
2615 talloc_free(failed_file);
2616 return rc;
Harald Welte3fb0b6f2010-05-19 19:02:52 +02002617}
2618
2619ALIAS(config_write_file,
2620 config_write_cmd,
2621 "write", "Write running configuration to memory, network, or terminal\n")
2622
2623 ALIAS(config_write_file,
2624 config_write_memory_cmd,
2625 "write memory",
2626 "Write running configuration to memory, network, or terminal\n"
2627 "Write configuration to the file (same as write file)\n")
2628
2629 ALIAS(config_write_file,
2630 copy_runningconfig_startupconfig_cmd,
2631 "copy running-config startup-config",
2632 "Copy configuration\n"
2633 "Copy running config to... \n"
2634 "Copy running config to startup config (same as write file)\n")
2635
2636/* Write current configuration into the terminal. */
2637 DEFUN(config_write_terminal,
2638 config_write_terminal_cmd,
2639 "write terminal",
2640 "Write running configuration to memory, network, or terminal\n"
2641 "Write to terminal\n")
2642{
2643 unsigned int i;
2644 struct cmd_node *node;
2645
2646 if (vty->type == VTY_SHELL_SERV) {
2647 for (i = 0; i < vector_active(cmdvec); i++)
2648 if ((node = vector_slot(cmdvec, i)) && node->func
2649 && node->vtysh) {
2650 if ((*node->func) (vty))
2651 vty_out(vty, "!%s", VTY_NEWLINE);
2652 }
2653 } else {
2654 vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2655 VTY_NEWLINE);
2656 vty_out(vty, "!%s", VTY_NEWLINE);
2657
2658 for (i = 0; i < vector_active(cmdvec); i++)
2659 if ((node = vector_slot(cmdvec, i)) && node->func) {
2660 if ((*node->func) (vty))
2661 vty_out(vty, "!%s", VTY_NEWLINE);
2662 }
2663 vty_out(vty, "end%s", VTY_NEWLINE);
2664 }
2665 return CMD_SUCCESS;
2666}
2667
2668/* Write current configuration into the terminal. */
2669ALIAS(config_write_terminal,
2670 show_running_config_cmd,
2671 "show running-config", SHOW_STR "running configuration\n")
2672
2673/* Write startup configuration into the terminal. */
2674 DEFUN(show_startup_config,
2675 show_startup_config_cmd,
2676 "show startup-config", SHOW_STR "Contentes of startup configuration\n")
2677{
2678 char buf[BUFSIZ];
2679 FILE *confp;
2680
2681 confp = fopen(host.config, "r");
2682 if (confp == NULL) {
2683 vty_out(vty, "Can't open configuration file [%s]%s",
2684 host.config, VTY_NEWLINE);
2685 return CMD_WARNING;
2686 }
2687
2688 while (fgets(buf, BUFSIZ, confp)) {
2689 char *cp = buf;
2690
2691 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2692 cp++;
2693 *cp = '\0';
2694
2695 vty_out(vty, "%s%s", buf, VTY_NEWLINE);
2696 }
2697
2698 fclose(confp);
2699
2700 return CMD_SUCCESS;
2701}
2702
2703/* Hostname configuration */
2704DEFUN(config_hostname,
2705 hostname_cmd,
2706 "hostname WORD",
2707 "Set system's network name\n" "This system's network name\n")
2708{
2709 if (!isalpha((int)*argv[0])) {
2710 vty_out(vty, "Please specify string starting with alphabet%s",
2711 VTY_NEWLINE);
2712 return CMD_WARNING;
2713 }
2714
2715 if (host.name)
2716 talloc_free(host.name);
2717
2718 host.name = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2719 return CMD_SUCCESS;
2720}
2721
2722DEFUN(config_no_hostname,
2723 no_hostname_cmd,
2724 "no hostname [HOSTNAME]",
2725 NO_STR "Reset system's network name\n" "Host name of this router\n")
2726{
2727 if (host.name)
2728 talloc_free(host.name);
2729 host.name = NULL;
2730 return CMD_SUCCESS;
2731}
2732
2733/* VTY interface password set. */
2734DEFUN(config_password, password_cmd,
2735 "password (8|) WORD",
2736 "Assign the terminal connection password\n"
2737 "Specifies a HIDDEN password will follow\n"
2738 "dummy string \n" "The HIDDEN line password string\n")
2739{
2740 /* Argument check. */
2741 if (argc == 0) {
2742 vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2743 return CMD_WARNING;
2744 }
2745
2746 if (argc == 2) {
2747 if (*argv[0] == '8') {
2748 if (host.password)
2749 talloc_free(host.password);
2750 host.password = NULL;
2751 if (host.password_encrypt)
2752 talloc_free(host.password_encrypt);
2753 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
2754 return CMD_SUCCESS;
2755 } else {
2756 vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2757 return CMD_WARNING;
2758 }
2759 }
2760
2761 if (!isalnum((int)*argv[0])) {
2762 vty_out(vty,
2763 "Please specify string starting with alphanumeric%s",
2764 VTY_NEWLINE);
2765 return CMD_WARNING;
2766 }
2767
2768 if (host.password)
2769 talloc_free(host.password);
2770 host.password = NULL;
2771
2772#ifdef VTY_CRYPT_PW
2773 if (host.encrypt) {
2774 if (host.password_encrypt)
2775 talloc_free(host.password_encrypt);
2776 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
2777 } else
2778#endif
2779 host.password = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2780
2781 return CMD_SUCCESS;
2782}
2783
2784ALIAS(config_password, password_text_cmd,
2785 "password LINE",
2786 "Assign the terminal connection password\n"
2787 "The UNENCRYPTED (cleartext) line password\n")
2788
2789/* VTY enable password set. */
2790 DEFUN(config_enable_password, enable_password_cmd,
2791 "enable password (8|) WORD",
2792 "Modify enable password parameters\n"
2793 "Assign the privileged level password\n"
2794 "Specifies a HIDDEN password will follow\n"
2795 "dummy string \n" "The HIDDEN 'enable' password string\n")
2796{
2797 /* Argument check. */
2798 if (argc == 0) {
2799 vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
2800 return CMD_WARNING;
2801 }
2802
2803 /* Crypt type is specified. */
2804 if (argc == 2) {
2805 if (*argv[0] == '8') {
2806 if (host.enable)
2807 talloc_free(host.enable);
2808 host.enable = NULL;
2809
2810 if (host.enable_encrypt)
2811 talloc_free(host.enable_encrypt);
2812 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, argv[1]);
2813
2814 return CMD_SUCCESS;
2815 } else {
2816 vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
2817 return CMD_WARNING;
2818 }
2819 }
2820
2821 if (!isalnum((int)*argv[0])) {
2822 vty_out(vty,
2823 "Please specify string starting with alphanumeric%s",
2824 VTY_NEWLINE);
2825 return CMD_WARNING;
2826 }
2827
2828 if (host.enable)
2829 talloc_free(host.enable);
2830 host.enable = NULL;
2831
2832 /* Plain password input. */
2833#ifdef VTY_CRYPT_PW
2834 if (host.encrypt) {
2835 if (host.enable_encrypt)
2836 talloc_free(host.enable_encrypt);
2837 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(argv[0]));
2838 } else
2839#endif
2840 host.enable = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
2841
2842 return CMD_SUCCESS;
2843}
2844
2845ALIAS(config_enable_password,
2846 enable_password_text_cmd,
2847 "enable password LINE",
2848 "Modify enable password parameters\n"
2849 "Assign the privileged level password\n"
2850 "The UNENCRYPTED (cleartext) 'enable' password\n")
2851
2852/* VTY enable password delete. */
2853 DEFUN(no_config_enable_password, no_enable_password_cmd,
2854 "no enable password",
2855 NO_STR
2856 "Modify enable password parameters\n"
2857 "Assign the privileged level password\n")
2858{
2859 if (host.enable)
2860 talloc_free(host.enable);
2861 host.enable = NULL;
2862
2863 if (host.enable_encrypt)
2864 talloc_free(host.enable_encrypt);
2865 host.enable_encrypt = NULL;
2866
2867 return CMD_SUCCESS;
2868}
2869
2870#ifdef VTY_CRYPT_PW
2871DEFUN(service_password_encrypt,
2872 service_password_encrypt_cmd,
2873 "service password-encryption",
2874 "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2875{
2876 if (host.encrypt)
2877 return CMD_SUCCESS;
2878
2879 host.encrypt = 1;
2880
2881 if (host.password) {
2882 if (host.password_encrypt)
2883 talloc_free(host.password_encrypt);
2884 host.password_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.password));
2885 }
2886 if (host.enable) {
2887 if (host.enable_encrypt)
2888 talloc_free(host.enable_encrypt);
2889 host.enable_encrypt = talloc_strdup(tall_vty_cmd_ctx, zencrypt(host.enable));
2890 }
2891
2892 return CMD_SUCCESS;
2893}
2894
2895DEFUN(no_service_password_encrypt,
2896 no_service_password_encrypt_cmd,
2897 "no service password-encryption",
2898 NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n")
2899{
2900 if (!host.encrypt)
2901 return CMD_SUCCESS;
2902
2903 host.encrypt = 0;
2904
2905 if (host.password_encrypt)
2906 talloc_free(host.password_encrypt);
2907 host.password_encrypt = NULL;
2908
2909 if (host.enable_encrypt)
2910 talloc_free(host.enable_encrypt);
2911 host.enable_encrypt = NULL;
2912
2913 return CMD_SUCCESS;
2914}
2915#endif
2916
2917DEFUN(config_terminal_length, config_terminal_length_cmd,
2918 "terminal length <0-512>",
2919 "Set terminal line parameters\n"
2920 "Set number of lines on a screen\n"
2921 "Number of lines on screen (0 for no pausing)\n")
2922{
2923 int lines;
2924 char *endptr = NULL;
2925
2926 lines = strtol(argv[0], &endptr, 10);
2927 if (lines < 0 || lines > 512 || *endptr != '\0') {
2928 vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2929 return CMD_WARNING;
2930 }
2931 vty->lines = lines;
2932
2933 return CMD_SUCCESS;
2934}
2935
2936DEFUN(config_terminal_no_length, config_terminal_no_length_cmd,
2937 "terminal no length",
2938 "Set terminal line parameters\n"
2939 NO_STR "Set number of lines on a screen\n")
2940{
2941 vty->lines = -1;
2942 return CMD_SUCCESS;
2943}
2944
2945DEFUN(service_terminal_length, service_terminal_length_cmd,
2946 "service terminal-length <0-512>",
2947 "Set up miscellaneous service\n"
2948 "System wide terminal length configuration\n"
2949 "Number of lines of VTY (0 means no line control)\n")
2950{
2951 int lines;
2952 char *endptr = NULL;
2953
2954 lines = strtol(argv[0], &endptr, 10);
2955 if (lines < 0 || lines > 512 || *endptr != '\0') {
2956 vty_out(vty, "length is malformed%s", VTY_NEWLINE);
2957 return CMD_WARNING;
2958 }
2959 host.lines = lines;
2960
2961 return CMD_SUCCESS;
2962}
2963
2964DEFUN(no_service_terminal_length, no_service_terminal_length_cmd,
2965 "no service terminal-length [<0-512>]",
2966 NO_STR
2967 "Set up miscellaneous service\n"
2968 "System wide terminal length configuration\n"
2969 "Number of lines of VTY (0 means no line control)\n")
2970{
2971 host.lines = -1;
2972 return CMD_SUCCESS;
2973}
2974
2975DEFUN_HIDDEN(do_echo,
2976 echo_cmd,
2977 "echo .MESSAGE",
2978 "Echo a message back to the vty\n" "The message to echo\n")
2979{
2980 char *message;
2981
2982 vty_out(vty, "%s%s",
2983 ((message =
2984 argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
2985 if (message)
2986 talloc_free(message);
2987 return CMD_SUCCESS;
2988}
2989
2990#if 0
2991DEFUN(config_logmsg,
2992 config_logmsg_cmd,
2993 "logmsg " LOG_LEVELS " .MESSAGE",
2994 "Send a message to enabled logging destinations\n"
2995 LOG_LEVEL_DESC "The message to send\n")
2996{
2997 int level;
2998 char *message;
2999
3000 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3001 return CMD_ERR_NO_MATCH;
3002
3003 zlog(NULL, level,
3004 ((message = argv_concat(argv, argc, 1)) ? message : ""));
3005 if (message)
3006 talloc_free(message);
3007 return CMD_SUCCESS;
3008}
3009
3010DEFUN(show_logging,
3011 show_logging_cmd,
3012 "show logging", SHOW_STR "Show current logging configuration\n")
3013{
3014 struct zlog *zl = zlog_default;
3015
3016 vty_out(vty, "Syslog logging: ");
3017 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3018 vty_out(vty, "disabled");
3019 else
3020 vty_out(vty, "level %s, facility %s, ident %s",
3021 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3022 facility_name(zl->facility), zl->ident);
3023 vty_out(vty, "%s", VTY_NEWLINE);
3024
3025 vty_out(vty, "Stdout logging: ");
3026 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3027 vty_out(vty, "disabled");
3028 else
3029 vty_out(vty, "level %s",
3030 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3031 vty_out(vty, "%s", VTY_NEWLINE);
3032
3033 vty_out(vty, "Monitor logging: ");
3034 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3035 vty_out(vty, "disabled");
3036 else
3037 vty_out(vty, "level %s",
3038 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3039 vty_out(vty, "%s", VTY_NEWLINE);
3040
3041 vty_out(vty, "File logging: ");
3042 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
3043 vty_out(vty, "disabled");
3044 else
3045 vty_out(vty, "level %s, filename %s",
3046 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3047 zl->filename);
3048 vty_out(vty, "%s", VTY_NEWLINE);
3049
3050 vty_out(vty, "Protocol name: %s%s",
3051 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3052 vty_out(vty, "Record priority: %s%s",
3053 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3054
3055 return CMD_SUCCESS;
3056}
3057
3058DEFUN(config_log_stdout,
3059 config_log_stdout_cmd,
3060 "log stdout", "Logging control\n" "Set stdout logging level\n")
3061{
3062 zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3063 return CMD_SUCCESS;
3064}
3065
3066DEFUN(config_log_stdout_level,
3067 config_log_stdout_level_cmd,
3068 "log stdout " LOG_LEVELS,
3069 "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC)
3070{
3071 int level;
3072
3073 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3074 return CMD_ERR_NO_MATCH;
3075 zlog_set_level(NULL, ZLOG_DEST_STDOUT, level);
3076 return CMD_SUCCESS;
3077}
3078
3079DEFUN(no_config_log_stdout,
3080 no_config_log_stdout_cmd,
3081 "no log stdout [LEVEL]",
3082 NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n")
3083{
3084 zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
3085 return CMD_SUCCESS;
3086}
3087
3088DEFUN(config_log_monitor,
3089 config_log_monitor_cmd,
3090 "log monitor",
3091 "Logging control\n" "Set terminal line (monitor) logging level\n")
3092{
3093 zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3094 return CMD_SUCCESS;
3095}
3096
3097DEFUN(config_log_monitor_level,
3098 config_log_monitor_level_cmd,
3099 "log monitor " LOG_LEVELS,
3100 "Logging control\n"
3101 "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
3102{
3103 int level;
3104
3105 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3106 return CMD_ERR_NO_MATCH;
3107 zlog_set_level(NULL, ZLOG_DEST_MONITOR, level);
3108 return CMD_SUCCESS;
3109}
3110
3111DEFUN(no_config_log_monitor,
3112 no_config_log_monitor_cmd,
3113 "no log monitor [LEVEL]",
3114 NO_STR
3115 "Logging control\n"
3116 "Disable terminal line (monitor) logging\n" "Logging level\n")
3117{
3118 zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3119 return CMD_SUCCESS;
3120}
3121
3122static int set_log_file(struct vty *vty, const char *fname, int loglevel)
3123{
3124 int ret;
3125 char *p = NULL;
3126 const char *fullpath;
3127
3128 /* Path detection. */
3129 if (!IS_DIRECTORY_SEP(*fname)) {
3130 char cwd[MAXPATHLEN + 1];
3131 cwd[MAXPATHLEN] = '\0';
3132
3133 if (getcwd(cwd, MAXPATHLEN) == NULL) {
3134 zlog_err("config_log_file: Unable to alloc mem!");
3135 return CMD_WARNING;
3136 }
3137
3138 if ((p = _talloc_zero(tall_vcmd_ctx,
3139 strlen(cwd) + strlen(fname) + 2),
3140 "set_log_file")
3141 == NULL) {
3142 zlog_err("config_log_file: Unable to alloc mem!");
3143 return CMD_WARNING;
3144 }
3145 sprintf(p, "%s/%s", cwd, fname);
3146 fullpath = p;
3147 } else
3148 fullpath = fname;
3149
3150 ret = zlog_set_file(NULL, fullpath, loglevel);
3151
3152 if (p)
3153 talloc_free(p);
3154
3155 if (!ret) {
3156 vty_out(vty, "can't open logfile %s\n", fname);
3157 return CMD_WARNING;
3158 }
3159
3160 if (host.logfile)
3161 talloc_free(host.logfile);
3162
3163 host.logfile = talloc_strdup(tall_vty_cmd_ctx, fname);
3164
3165 return CMD_SUCCESS;
3166}
3167
3168DEFUN(config_log_file,
3169 config_log_file_cmd,
3170 "log file FILENAME",
3171 "Logging control\n" "Logging to file\n" "Logging filename\n")
3172{
3173 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3174}
3175
3176DEFUN(config_log_file_level,
3177 config_log_file_level_cmd,
3178 "log file FILENAME " LOG_LEVELS,
3179 "Logging control\n"
3180 "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC)
3181{
3182 int level;
3183
3184 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3185 return CMD_ERR_NO_MATCH;
3186 return set_log_file(vty, argv[0], level);
3187}
3188
3189DEFUN(no_config_log_file,
3190 no_config_log_file_cmd,
3191 "no log file [FILENAME]",
3192 NO_STR
3193 "Logging control\n" "Cancel logging to file\n" "Logging file name\n")
3194{
3195 zlog_reset_file(NULL);
3196
3197 if (host.logfile)
3198 talloc_free(host.logfile);
3199
3200 host.logfile = NULL;
3201
3202 return CMD_SUCCESS;
3203}
3204
3205ALIAS(no_config_log_file,
3206 no_config_log_file_level_cmd,
3207 "no log file FILENAME LEVEL",
3208 NO_STR
3209 "Logging control\n"
3210 "Cancel logging to file\n" "Logging file name\n" "Logging level\n")
3211
3212 DEFUN(config_log_syslog,
3213 config_log_syslog_cmd,
3214 "log syslog", "Logging control\n" "Set syslog logging level\n")
3215{
3216 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3217 return CMD_SUCCESS;
3218}
3219
3220DEFUN(config_log_syslog_level,
3221 config_log_syslog_level_cmd,
3222 "log syslog " LOG_LEVELS,
3223 "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC)
3224{
3225 int level;
3226
3227 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3228 return CMD_ERR_NO_MATCH;
3229 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level);
3230 return CMD_SUCCESS;
3231}
3232
3233DEFUN_DEPRECATED(config_log_syslog_facility,
3234 config_log_syslog_facility_cmd,
3235 "log syslog facility " LOG_FACILITIES,
3236 "Logging control\n"
3237 "Logging goes to syslog\n"
3238 "(Deprecated) Facility parameter for syslog messages\n"
3239 LOG_FACILITY_DESC)
3240{
3241 int facility;
3242
3243 if ((facility = facility_match(argv[0])) < 0)
3244 return CMD_ERR_NO_MATCH;
3245
3246 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
3247 zlog_default->facility = facility;
3248 return CMD_SUCCESS;
3249}
3250
3251DEFUN(no_config_log_syslog,
3252 no_config_log_syslog_cmd,
3253 "no log syslog [LEVEL]",
3254 NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n")
3255{
3256 zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
3257 return CMD_SUCCESS;
3258}
3259
3260ALIAS(no_config_log_syslog,
3261 no_config_log_syslog_facility_cmd,
3262 "no log syslog facility " LOG_FACILITIES,
3263 NO_STR
3264 "Logging control\n"
3265 "Logging goes to syslog\n"
3266 "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3267
3268 DEFUN(config_log_facility,
3269 config_log_facility_cmd,
3270 "log facility " LOG_FACILITIES,
3271 "Logging control\n"
3272 "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
3273{
3274 int facility;
3275
3276 if ((facility = facility_match(argv[0])) < 0)
3277 return CMD_ERR_NO_MATCH;
3278 zlog_default->facility = facility;
3279 return CMD_SUCCESS;
3280}
3281
3282DEFUN(no_config_log_facility,
3283 no_config_log_facility_cmd,
3284 "no log facility [FACILITY]",
3285 NO_STR
3286 "Logging control\n"
3287 "Reset syslog facility to default (daemon)\n" "Syslog facility\n")
3288{
3289 zlog_default->facility = LOG_DAEMON;
3290 return CMD_SUCCESS;
3291}
3292
3293DEFUN_DEPRECATED(config_log_trap,
3294 config_log_trap_cmd,
3295 "log trap " LOG_LEVELS,
3296 "Logging control\n"
3297 "(Deprecated) Set logging level and default for all destinations\n"
3298 LOG_LEVEL_DESC)
3299{
3300 int new_level;
3301 int i;
3302
3303 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3304 return CMD_ERR_NO_MATCH;
3305
3306 zlog_default->default_lvl = new_level;
3307 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3308 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3309 zlog_default->maxlvl[i] = new_level;
3310 return CMD_SUCCESS;
3311}
3312
3313DEFUN_DEPRECATED(no_config_log_trap,
3314 no_config_log_trap_cmd,
3315 "no log trap [LEVEL]",
3316 NO_STR
3317 "Logging control\n"
3318 "Permit all logging information\n" "Logging level\n")
3319{
3320 zlog_default->default_lvl = LOG_DEBUG;
3321 return CMD_SUCCESS;
3322}
3323
3324DEFUN(config_log_record_priority,
3325 config_log_record_priority_cmd,
3326 "log record-priority",
3327 "Logging control\n"
3328 "Log the priority of the message within the message\n")
3329{
3330 zlog_default->record_priority = 1;
3331 return CMD_SUCCESS;
3332}
3333
3334DEFUN(no_config_log_record_priority,
3335 no_config_log_record_priority_cmd,
3336 "no log record-priority",
3337 NO_STR
3338 "Logging control\n"
3339 "Do not log the priority of the message within the message\n")
3340{
3341 zlog_default->record_priority = 0;
3342 return CMD_SUCCESS;
3343}
3344#endif
3345
3346DEFUN(banner_motd_file,
3347 banner_motd_file_cmd,
3348 "banner motd file [FILE]",
3349 "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
3350{
3351 if (host.motdfile)
3352 talloc_free(host.motdfile);
3353 host.motdfile = talloc_strdup(tall_vty_cmd_ctx, argv[0]);
3354
3355 return CMD_SUCCESS;
3356}
3357
3358DEFUN(banner_motd_default,
3359 banner_motd_default_cmd,
3360 "banner motd default",
3361 "Set banner string\n" "Strings for motd\n" "Default string\n")
3362{
3363 host.motd = default_motd;
3364 return CMD_SUCCESS;
3365}
3366
3367DEFUN(no_banner_motd,
3368 no_banner_motd_cmd,
3369 "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n")
3370{
3371 host.motd = NULL;
3372 if (host.motdfile)
3373 talloc_free(host.motdfile);
3374 host.motdfile = NULL;
3375 return CMD_SUCCESS;
3376}
3377
3378/* Set config filename. Called from vty.c */
3379void host_config_set(const char *filename)
3380{
3381 host.config = talloc_strdup(tall_vty_cmd_ctx, filename);
3382}
3383
Holger Hans Peter Freythera9e52522015-08-02 02:14:07 +00003384void install_default(int node)
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003385{
3386 install_element(node, &config_help_cmd);
3387 install_element(node, &config_list_cmd);
3388
3389 install_element(node, &config_write_terminal_cmd);
3390 install_element(node, &config_write_file_cmd);
3391 install_element(node, &config_write_memory_cmd);
3392 install_element(node, &config_write_cmd);
3393 install_element(node, &show_running_config_cmd);
3394}
3395
Holger Hans Peter Freythera9e52522015-08-02 02:14:07 +00003396void vty_install_default(int node)
Jacob Erlbeck0c987bd2013-09-06 16:52:00 +02003397{
3398 install_default(node);
3399
3400 install_element(node, &config_exit_cmd);
3401
3402 if (node >= CONFIG_NODE) {
3403 /* It's not a top node. */
3404 install_element(node, &config_end_cmd);
3405 }
3406}
3407
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01003408/**
Neels Hofmeyr87e45502017-06-20 00:17:59 +02003409 * Write the current running config to a given file
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01003410 * \param[in] vty the vty of the code
3411 * \param[in] filename where to store the file
3412 * \return 0 in case of success.
3413 *
3414 * If the filename already exists create a filename.sav
3415 * version with the current code.
3416 *
3417 */
3418int osmo_vty_write_config_file(const char *filename)
3419{
3420 char *failed_file;
3421 int rc;
3422
3423 rc = write_config_file(filename, &failed_file);
3424 talloc_free(failed_file);
3425 return rc;
3426}
3427
3428/**
Neels Hofmeyr87e45502017-06-20 00:17:59 +02003429 * Save the current state to the config file
Holger Hans Peter Freyther738f1332012-03-24 18:26:24 +01003430 * \return 0 in case of success.
3431 *
3432 * If the filename already exists create a filename.sav
3433 * version with the current code.
3434 *
3435 */
3436int osmo_vty_save_config_file(void)
3437{
3438 char *failed_file;
3439 int rc;
3440
3441 if (host.config == NULL)
3442 return -7;
3443
3444 rc = write_config_file(host.config, &failed_file);
3445 talloc_free(failed_file);
3446 return rc;
3447}
3448
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003449/* Initialize command interface. Install basic nodes and commands. */
3450void cmd_init(int terminal)
3451{
3452 /* Allocate initial top vector of commands. */
3453 cmdvec = vector_init(VECTOR_MIN_SIZE);
3454
3455 /* Default host value settings. */
3456 host.name = NULL;
3457 host.password = NULL;
3458 host.enable = NULL;
3459 host.logfile = NULL;
3460 host.config = NULL;
3461 host.lines = -1;
3462 host.motd = default_motd;
3463 host.motdfile = NULL;
3464
3465 /* Install top nodes. */
3466 install_node(&view_node, NULL);
3467 install_node(&enable_node, NULL);
3468 install_node(&auth_node, NULL);
3469 install_node(&auth_enable_node, NULL);
3470 install_node(&config_node, config_write_host);
3471
3472 /* Each node's basic commands. */
3473 install_element(VIEW_NODE, &show_version_cmd);
Holger Hans Peter Freyther8297c812011-11-18 23:14:24 +01003474 install_element(VIEW_NODE, &show_online_help_cmd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003475 if (terminal) {
3476 install_element(VIEW_NODE, &config_list_cmd);
3477 install_element(VIEW_NODE, &config_exit_cmd);
3478 install_element(VIEW_NODE, &config_help_cmd);
3479 install_element(VIEW_NODE, &config_enable_cmd);
3480 install_element(VIEW_NODE, &config_terminal_length_cmd);
3481 install_element(VIEW_NODE, &config_terminal_no_length_cmd);
3482 install_element(VIEW_NODE, &echo_cmd);
3483 }
3484
3485 if (terminal) {
Jacob Erlbeck0c987bd2013-09-06 16:52:00 +02003486 vty_install_default(ENABLE_NODE);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003487 install_element(ENABLE_NODE, &config_disable_cmd);
3488 install_element(ENABLE_NODE, &config_terminal_cmd);
3489 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3490 }
3491 install_element (ENABLE_NODE, &show_startup_config_cmd);
3492 install_element(ENABLE_NODE, &show_version_cmd);
Holger Hans Peter Freyther8297c812011-11-18 23:14:24 +01003493 install_element(ENABLE_NODE, &show_online_help_cmd);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003494
3495 if (terminal) {
3496 install_element(ENABLE_NODE, &config_terminal_length_cmd);
3497 install_element(ENABLE_NODE, &config_terminal_no_length_cmd);
3498 install_element(ENABLE_NODE, &echo_cmd);
3499
Jacob Erlbeck0c987bd2013-09-06 16:52:00 +02003500 vty_install_default(CONFIG_NODE);
Harald Welte3fb0b6f2010-05-19 19:02:52 +02003501 }
3502
3503 install_element(CONFIG_NODE, &hostname_cmd);
3504 install_element(CONFIG_NODE, &no_hostname_cmd);
3505
3506 if (terminal) {
3507 install_element(CONFIG_NODE, &password_cmd);
3508 install_element(CONFIG_NODE, &password_text_cmd);
3509 install_element(CONFIG_NODE, &enable_password_cmd);
3510 install_element(CONFIG_NODE, &enable_password_text_cmd);
3511 install_element(CONFIG_NODE, &no_enable_password_cmd);
3512
3513#ifdef VTY_CRYPT_PW
3514 install_element(CONFIG_NODE, &service_password_encrypt_cmd);
3515 install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
3516#endif
3517 install_element(CONFIG_NODE, &banner_motd_default_cmd);
3518 install_element(CONFIG_NODE, &banner_motd_file_cmd);
3519 install_element(CONFIG_NODE, &no_banner_motd_cmd);
3520 install_element(CONFIG_NODE, &service_terminal_length_cmd);
3521 install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
3522
3523 }
3524 srand(time(NULL));
3525}
Harald Welte7acb30c2011-08-17 17:13:48 +02003526
Sylvain Munautdca7d2c2012-04-18 21:53:23 +02003527/*! @} */