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