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