blob: fc115d95ed9abf502ac15fa62151fa3e99bd3b0c [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Command interpreter routine for virtual terminal [aka TeletYpe]
2 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published
8by the Free Software Foundation; either version 2, or (at your
9option) any later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include <zebra.h>
22
paulb21b19c2003-06-15 01:28:29 +000023
paul718e3742002-12-13 20:15:29 +000024#include "memory.h"
25#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000026#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000027#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000028#include "vector.h"
29#include "vty.h"
30#include "command.h"
paul718e3742002-12-13 20:15:29 +000031
32/* Command vector which includes some level of command lists. Normally
33 each daemon maintains each own cmdvec. */
34vector cmdvec;
35
36/* Host information structure. */
37struct host host;
38
paul718e3742002-12-13 20:15:29 +000039/* Standard command node structures. */
40struct cmd_node auth_node =
41{
42 AUTH_NODE,
43 "Password: ",
44};
45
46struct cmd_node view_node =
47{
48 VIEW_NODE,
49 "%s> ",
50};
51
52struct cmd_node auth_enable_node =
53{
54 AUTH_ENABLE_NODE,
55 "Password: ",
56};
57
58struct cmd_node enable_node =
59{
60 ENABLE_NODE,
61 "%s# ",
62};
63
64struct cmd_node config_node =
65{
66 CONFIG_NODE,
67 "%s(config)# ",
68 1
69};
hasso6590f2c2004-10-19 20:40:08 +000070
71/* Default motd string. */
72const char *default_motd =
73"\r\n\
74Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
75" QUAGGA_COPYRIGHT "\r\n\
76\r\n";
77
78void
79print_version (const char *progname)
80{
81 printf ("%s version %s (%s)\n", progname, QUAGGA_VERSION, host.name);
82 printf ("%s\n", QUAGGA_COPYRIGHT);
83}
84
paul718e3742002-12-13 20:15:29 +000085
86/* Utility function to concatenate argv argument into a single string
87 with inserting ' ' character between each argument. */
88char *
paul42d49862004-10-13 05:22:18 +000089argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +000090{
91 int i;
92 int len;
93 int index;
94 char *str;
95
96 str = NULL;
97 index = 0;
98
99 for (i = shift; i < argc; i++)
100 {
101 len = strlen (argv[i]);
102
103 if (i == shift)
104 {
105 str = XSTRDUP (MTYPE_TMP, argv[i]);
106 index = len;
107 }
108 else
109 {
110 str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
111 str[index++] = ' ';
112 memcpy (str + index, argv[i], len);
113 index += len;
114 str[index] = '\0';
115 }
116 }
117 return str;
118}
119
120/* Install top node of command vector. */
121void
122install_node (struct cmd_node *node,
123 int (*func) (struct vty *))
124{
125 vector_set_index (cmdvec, node->node, node);
126 node->func = func;
127 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
128}
129
130/* Compare two command's string. Used in sort_node (). */
131int
132cmp_node (const void *p, const void *q)
133{
134 struct cmd_element *a = *(struct cmd_element **)p;
135 struct cmd_element *b = *(struct cmd_element **)q;
136
137 return strcmp (a->string, b->string);
138}
139
140int
141cmp_desc (const void *p, const void *q)
142{
143 struct desc *a = *(struct desc **)p;
144 struct desc *b = *(struct desc **)q;
145
146 return strcmp (a->cmd, b->cmd);
147}
148
149/* Sort each node's command element according to command string. */
150void
151sort_node ()
152{
hasso8c328f12004-10-05 21:01:23 +0000153 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000154 struct cmd_node *cnode;
155 vector descvec;
156 struct cmd_element *cmd_element;
157
158 for (i = 0; i < vector_max (cmdvec); i++)
159 if ((cnode = vector_slot (cmdvec, i)) != NULL)
160 {
161 vector cmd_vector = cnode->cmd_vector;
162 qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
163
164 for (j = 0; j < vector_max (cmd_vector); j++)
165 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
166 {
167 descvec = vector_slot (cmd_element->strvec,
168 vector_max (cmd_element->strvec) - 1);
169 qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
170 }
171 }
172}
173
174/* Breaking up string into each command piece. I assume given
175 character is separated by a space character. Return value is a
176 vector which includes char ** data element. */
177vector
hassoea8e9d92004-10-07 21:32:14 +0000178cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000179{
hassoea8e9d92004-10-07 21:32:14 +0000180 const char *cp, *start;
181 char *token;
paul718e3742002-12-13 20:15:29 +0000182 int strlen;
183 vector strvec;
184
185 if (string == NULL)
186 return NULL;
187
188 cp = string;
189
190 /* Skip white spaces. */
191 while (isspace ((int) *cp) && *cp != '\0')
192 cp++;
193
194 /* Return if there is only white spaces */
195 if (*cp == '\0')
196 return NULL;
197
198 if (*cp == '!' || *cp == '#')
199 return NULL;
200
201 /* Prepare return vector. */
202 strvec = vector_init (VECTOR_MIN_SIZE);
203
204 /* Copy each command piece and set into vector. */
205 while (1)
206 {
207 start = cp;
208 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
209 *cp != '\0')
210 cp++;
211 strlen = cp - start;
212 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
213 memcpy (token, start, strlen);
214 *(token + strlen) = '\0';
215 vector_set (strvec, token);
216
217 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
218 *cp != '\0')
219 cp++;
220
221 if (*cp == '\0')
222 return strvec;
223 }
224}
225
226/* Free allocated string vector. */
227void
228cmd_free_strvec (vector v)
229{
hasso8c328f12004-10-05 21:01:23 +0000230 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000231 char *cp;
232
233 if (!v)
234 return;
235
236 for (i = 0; i < vector_max (v); i++)
237 if ((cp = vector_slot (v, i)) != NULL)
238 XFREE (MTYPE_STRVEC, cp);
239
240 vector_free (v);
241}
242
243/* Fetch next description. Used in cmd_make_descvec(). */
244char *
hasso6ad96ea2004-10-07 19:33:46 +0000245cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000246{
hasso6ad96ea2004-10-07 19:33:46 +0000247 const char *cp, *start;
248 char *token;
paul718e3742002-12-13 20:15:29 +0000249 int strlen;
250
251 cp = *string;
252
253 if (cp == NULL)
254 return NULL;
255
256 /* Skip white spaces. */
257 while (isspace ((int) *cp) && *cp != '\0')
258 cp++;
259
260 /* Return if there is only white spaces */
261 if (*cp == '\0')
262 return NULL;
263
264 start = cp;
265
266 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
267 cp++;
268
269 strlen = cp - start;
270 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
271 memcpy (token, start, strlen);
272 *(token + strlen) = '\0';
273
274 *string = cp;
275
276 return token;
277}
278
279/* New string vector. */
280vector
hasso8c328f12004-10-05 21:01:23 +0000281cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000282{
283 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000284 const char *sp;
paul718e3742002-12-13 20:15:29 +0000285 char *token;
286 int len;
hasso8c328f12004-10-05 21:01:23 +0000287 const char *cp;
288 const char *dp;
paul718e3742002-12-13 20:15:29 +0000289 vector allvec;
290 vector strvec = NULL;
291 struct desc *desc;
292
293 cp = string;
294 dp = descstr;
295
296 if (cp == NULL)
297 return NULL;
298
299 allvec = vector_init (VECTOR_MIN_SIZE);
300
301 while (1)
302 {
303 while (isspace ((int) *cp) && *cp != '\0')
304 cp++;
305
306 if (*cp == '(')
307 {
308 multiple = 1;
309 cp++;
310 }
311 if (*cp == ')')
312 {
313 multiple = 0;
314 cp++;
315 }
316 if (*cp == '|')
317 {
318 if (! multiple)
319 {
320 fprintf (stderr, "Command parse error!: %s\n", string);
321 exit (1);
322 }
323 cp++;
324 }
325
326 while (isspace ((int) *cp) && *cp != '\0')
327 cp++;
328
329 if (*cp == '(')
330 {
331 multiple = 1;
332 cp++;
333 }
334
335 if (*cp == '\0')
336 return allvec;
337
338 sp = cp;
339
340 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
341 cp++;
342
343 len = cp - sp;
344
345 token = XMALLOC (MTYPE_STRVEC, len + 1);
346 memcpy (token, sp, len);
347 *(token + len) = '\0';
348
349 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
350 desc->cmd = token;
351 desc->str = cmd_desc_str (&dp);
352
353 if (multiple)
354 {
355 if (multiple == 1)
356 {
357 strvec = vector_init (VECTOR_MIN_SIZE);
358 vector_set (allvec, strvec);
359 }
360 multiple++;
361 }
362 else
363 {
364 strvec = vector_init (VECTOR_MIN_SIZE);
365 vector_set (allvec, strvec);
366 }
367 vector_set (strvec, desc);
368 }
369}
370
371/* Count mandantory string vector size. This is to determine inputed
372 command has enough command length. */
373int
374cmd_cmdsize (vector strvec)
375{
hasso8c328f12004-10-05 21:01:23 +0000376 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000377 int size = 0;
378 vector descvec;
379
380 for (i = 0; i < vector_max (strvec); i++)
381 {
382 descvec = vector_slot (strvec, i);
383
384 if (vector_max (descvec) == 1)
385 {
386 struct desc *desc = vector_slot (descvec, 0);
387
hasso8c328f12004-10-05 21:01:23 +0000388 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000389 return size;
390 else
391 size++;
392 }
393 else
394 size++;
395 }
396 return size;
397}
398
399/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000400const char *
paul718e3742002-12-13 20:15:29 +0000401cmd_prompt (enum node_type node)
402{
403 struct cmd_node *cnode;
404
405 cnode = vector_slot (cmdvec, node);
406 return cnode->prompt;
407}
408
409/* Install a command into a node. */
410void
411install_element (enum node_type ntype, struct cmd_element *cmd)
412{
413 struct cmd_node *cnode;
414
415 cnode = vector_slot (cmdvec, ntype);
416
417 if (cnode == NULL)
418 {
419 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
420 ntype);
421 exit (1);
422 }
423
424 vector_set (cnode->cmd_vector, cmd);
425
426 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
427 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
428}
429
430static unsigned char itoa64[] =
431"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
432
433void
434to64(char *s, long v, int n)
435{
436 while (--n >= 0)
437 {
438 *s++ = itoa64[v&0x3f];
439 v >>= 6;
440 }
441}
442
paul9035efa2004-10-10 11:56:56 +0000443char *zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000444{
445 char salt[6];
446 struct timeval tv;
447 char *crypt (const char *, const char *);
448
449 gettimeofday(&tv,0);
450
451 to64(&salt[0], random(), 3);
452 to64(&salt[3], tv.tv_usec, 3);
453 salt[5] = '\0';
454
455 return crypt (passwd, salt);
456}
457
hasso8c328f12004-10-05 21:01:23 +0000458const char *
paul12ab19f2003-07-26 06:14:55 +0000459syslog_facility_print (int facility)
460{
461 switch (facility)
462 {
463 case LOG_KERN:
464 return "kern";
465 break;
466 case LOG_USER:
467 return "user";
468 break;
469 case LOG_MAIL:
470 return "mail";
471 break;
472 case LOG_DAEMON:
473 return "daemon";
474 break;
475 case LOG_AUTH:
476 return "auth";
477 break;
478 case LOG_SYSLOG:
479 return "syslog";
480 break;
481 case LOG_LPR:
482 return "lpr";
483 break;
484 case LOG_NEWS:
485 return "news";
486 break;
487 case LOG_UUCP:
488 return "uucp";
489 break;
490 case LOG_CRON:
491 return "cron";
492 break;
493 case LOG_LOCAL0:
494 return "local0";
495 break;
496 case LOG_LOCAL1:
497 return "local1";
498 break;
499 case LOG_LOCAL2:
500 return "local2";
501 break;
502 case LOG_LOCAL3:
503 return "local3";
504 break;
505 case LOG_LOCAL4:
506 return "local4";
507 break;
508 case LOG_LOCAL5:
509 return "local5";
510 break;
511 case LOG_LOCAL6:
512 return "local6";
513 break;
514 case LOG_LOCAL7:
515 return "local7";
516 break;
517 default:
518 break;
519 }
520 return "";
521}
522
paul718e3742002-12-13 20:15:29 +0000523/* This function write configuration of this host. */
524int
525config_write_host (struct vty *vty)
526{
527 if (host.name)
528 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
529
530 if (host.encrypt)
531 {
532 if (host.password_encrypt)
533 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
534 if (host.enable_encrypt)
535 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
536 }
537 else
538 {
539 if (host.password)
540 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
541 if (host.enable)
542 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
543 }
544
545 if (host.logfile)
546 vty_out (vty, "log file %s%s", host.logfile, VTY_NEWLINE);
547
548 if (host.log_stdout)
549 vty_out (vty, "log stdout%s", VTY_NEWLINE);
550
551 if (host.log_syslog)
paul12ab19f2003-07-26 06:14:55 +0000552 {
553 vty_out (vty, "log syslog");
554 if (zlog_default->facility != LOG_DAEMON)
555 vty_out (vty, " facility %s", syslog_facility_print (zlog_default->facility));
556 vty_out (vty, "%s", VTY_NEWLINE);
557 }
paul718e3742002-12-13 20:15:29 +0000558 if (zlog_default->maskpri != LOG_DEBUG)
559 vty_out (vty, "log trap %s%s", zlog_priority[zlog_default->maskpri], VTY_NEWLINE);
560
561 if (zlog_default->record_priority == 1)
562 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
563
564 if (host.advanced)
565 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
566
567 if (host.encrypt)
568 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
569
570 if (host.lines >= 0)
571 vty_out (vty, "service terminal-length %d%s", host.lines,
572 VTY_NEWLINE);
573
574 if (! host.motd)
575 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
576
577 return 1;
578}
579
580/* Utility function for getting command vector. */
581vector
582cmd_node_vector (vector v, enum node_type ntype)
583{
584 struct cmd_node *cnode = vector_slot (v, ntype);
585 return cnode->cmd_vector;
586}
587
588/* Filter command vector by symbol */
589int
590cmd_filter_by_symbol (char *command, char *symbol)
591{
592 int i, lim;
593
594 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
595 {
596 i = 0;
597 lim = strlen (command);
598 while (i < lim)
599 {
600 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
601 return 1;
602 i++;
603 }
604 return 0;
605 }
606 if (strcmp (symbol, "STRING") == 0)
607 {
608 i = 0;
609 lim = strlen (command);
610 while (i < lim)
611 {
612 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
613 return 1;
614 i++;
615 }
616 return 0;
617 }
618 if (strcmp (symbol, "IFNAME") == 0)
619 {
620 i = 0;
621 lim = strlen (command);
622 while (i < lim)
623 {
624 if (! isalnum ((int) command[i]))
625 return 1;
626 i++;
627 }
628 return 0;
629 }
630 return 0;
631}
632
633/* Completion match types. */
634enum match_type
635{
636 no_match,
637 extend_match,
638 ipv4_prefix_match,
639 ipv4_match,
640 ipv6_prefix_match,
641 ipv6_match,
642 range_match,
643 vararg_match,
644 partly_match,
645 exact_match
646};
647
648enum match_type
hasso8c328f12004-10-05 21:01:23 +0000649cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000650{
hasso8c328f12004-10-05 21:01:23 +0000651 const char *sp;
paul718e3742002-12-13 20:15:29 +0000652 int dots = 0, nums = 0;
653 char buf[4];
654
655 if (str == NULL)
656 return partly_match;
657
658 for (;;)
659 {
660 memset (buf, 0, sizeof (buf));
661 sp = str;
662 while (*str != '\0')
663 {
664 if (*str == '.')
665 {
666 if (dots >= 3)
667 return no_match;
668
669 if (*(str + 1) == '.')
670 return no_match;
671
672 if (*(str + 1) == '\0')
673 return partly_match;
674
675 dots++;
676 break;
677 }
678 if (!isdigit ((int) *str))
679 return no_match;
680
681 str++;
682 }
683
684 if (str - sp > 3)
685 return no_match;
686
687 strncpy (buf, sp, str - sp);
688 if (atoi (buf) > 255)
689 return no_match;
690
691 nums++;
692
693 if (*str == '\0')
694 break;
695
696 str++;
697 }
698
699 if (nums < 4)
700 return partly_match;
701
702 return exact_match;
703}
704
705enum match_type
hasso8c328f12004-10-05 21:01:23 +0000706cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000707{
hasso8c328f12004-10-05 21:01:23 +0000708 const char *sp;
paul718e3742002-12-13 20:15:29 +0000709 int dots = 0;
710 char buf[4];
711
712 if (str == NULL)
713 return partly_match;
714
715 for (;;)
716 {
717 memset (buf, 0, sizeof (buf));
718 sp = str;
719 while (*str != '\0' && *str != '/')
720 {
721 if (*str == '.')
722 {
723 if (dots == 3)
724 return no_match;
725
726 if (*(str + 1) == '.' || *(str + 1) == '/')
727 return no_match;
728
729 if (*(str + 1) == '\0')
730 return partly_match;
731
732 dots++;
733 break;
734 }
735
736 if (!isdigit ((int) *str))
737 return no_match;
738
739 str++;
740 }
741
742 if (str - sp > 3)
743 return no_match;
744
745 strncpy (buf, sp, str - sp);
746 if (atoi (buf) > 255)
747 return no_match;
748
749 if (dots == 3)
750 {
751 if (*str == '/')
752 {
753 if (*(str + 1) == '\0')
754 return partly_match;
755
756 str++;
757 break;
758 }
759 else if (*str == '\0')
760 return partly_match;
761 }
762
763 if (*str == '\0')
764 return partly_match;
765
766 str++;
767 }
768
769 sp = str;
770 while (*str != '\0')
771 {
772 if (!isdigit ((int) *str))
773 return no_match;
774
775 str++;
776 }
777
778 if (atoi (sp) > 32)
779 return no_match;
780
781 return exact_match;
782}
783
784#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
785#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
786#define STATE_START 1
787#define STATE_COLON 2
788#define STATE_DOUBLE 3
789#define STATE_ADDR 4
790#define STATE_DOT 5
791#define STATE_SLASH 6
792#define STATE_MASK 7
793
paul22e0a9e2003-07-11 17:55:46 +0000794#ifdef HAVE_IPV6
795
paul718e3742002-12-13 20:15:29 +0000796enum match_type
hasso8c328f12004-10-05 21:01:23 +0000797cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000798{
799 int state = STATE_START;
800 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000801 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000802 struct sockaddr_in6 sin6_dummy;
803 int ret;
paul718e3742002-12-13 20:15:29 +0000804
805 if (str == NULL)
806 return partly_match;
807
808 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
809 return no_match;
810
hasso726f9b22003-05-25 21:04:54 +0000811 /* use inet_pton that has a better support,
812 * for example inet_pton can support the automatic addresses:
813 * ::1.2.3.4
814 */
815 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
816
817 if (ret == 1)
818 return exact_match;
819
paul718e3742002-12-13 20:15:29 +0000820 while (*str != '\0')
821 {
822 switch (state)
823 {
824 case STATE_START:
825 if (*str == ':')
826 {
827 if (*(str + 1) != ':' && *(str + 1) != '\0')
828 return no_match;
829 colons--;
830 state = STATE_COLON;
831 }
832 else
833 {
834 sp = str;
835 state = STATE_ADDR;
836 }
837
838 continue;
839 case STATE_COLON:
840 colons++;
841 if (*(str + 1) == ':')
842 state = STATE_DOUBLE;
843 else
844 {
845 sp = str + 1;
846 state = STATE_ADDR;
847 }
848 break;
849 case STATE_DOUBLE:
850 if (double_colon)
851 return no_match;
852
853 if (*(str + 1) == ':')
854 return no_match;
855 else
856 {
857 if (*(str + 1) != '\0')
858 colons++;
859 sp = str + 1;
860 state = STATE_ADDR;
861 }
862
863 double_colon++;
864 nums++;
865 break;
866 case STATE_ADDR:
867 if (*(str + 1) == ':' || *(str + 1) == '\0')
868 {
869 if (str - sp > 3)
870 return no_match;
871
872 nums++;
873 state = STATE_COLON;
874 }
875 if (*(str + 1) == '.')
876 state = STATE_DOT;
877 break;
878 case STATE_DOT:
879 state = STATE_ADDR;
880 break;
881 default:
882 break;
883 }
884
885 if (nums > 8)
886 return no_match;
887
888 if (colons > 7)
889 return no_match;
890
891 str++;
892 }
893
894#if 0
895 if (nums < 11)
896 return partly_match;
897#endif /* 0 */
898
899 return exact_match;
900}
901
902enum match_type
hasso8c328f12004-10-05 21:01:23 +0000903cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000904{
905 int state = STATE_START;
906 int colons = 0, nums = 0, double_colon = 0;
907 int mask;
hasso8c328f12004-10-05 21:01:23 +0000908 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000909 char *endptr = NULL;
910
911 if (str == NULL)
912 return partly_match;
913
914 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
915 return no_match;
916
917 while (*str != '\0' && state != STATE_MASK)
918 {
919 switch (state)
920 {
921 case STATE_START:
922 if (*str == ':')
923 {
924 if (*(str + 1) != ':' && *(str + 1) != '\0')
925 return no_match;
926 colons--;
927 state = STATE_COLON;
928 }
929 else
930 {
931 sp = str;
932 state = STATE_ADDR;
933 }
934
935 continue;
936 case STATE_COLON:
937 colons++;
938 if (*(str + 1) == '/')
939 return no_match;
940 else if (*(str + 1) == ':')
941 state = STATE_DOUBLE;
942 else
943 {
944 sp = str + 1;
945 state = STATE_ADDR;
946 }
947 break;
948 case STATE_DOUBLE:
949 if (double_colon)
950 return no_match;
951
952 if (*(str + 1) == ':')
953 return no_match;
954 else
955 {
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 {
973 if (str - sp > 3)
974 return no_match;
975
976 for (; sp <= str; sp++)
977 if (*sp == '/')
978 return no_match;
979
980 nums++;
981
982 if (*(str + 1) == ':')
983 state = STATE_COLON;
984 else if (*(str + 1) == '.')
985 state = STATE_DOT;
986 else if (*(str + 1) == '/')
987 state = STATE_SLASH;
988 }
989 break;
990 case STATE_DOT:
991 state = STATE_ADDR;
992 break;
993 case STATE_SLASH:
994 if (*(str + 1) == '\0')
995 return partly_match;
996
997 state = STATE_MASK;
998 break;
999 default:
1000 break;
1001 }
1002
1003 if (nums > 11)
1004 return no_match;
1005
1006 if (colons > 7)
1007 return no_match;
1008
1009 str++;
1010 }
1011
1012 if (state < STATE_MASK)
1013 return partly_match;
1014
1015 mask = strtol (str, &endptr, 10);
1016 if (*endptr != '\0')
1017 return no_match;
1018
1019 if (mask < 0 || mask > 128)
1020 return no_match;
1021
1022/* I don't know why mask < 13 makes command match partly.
1023 Forgive me to make this comments. I Want to set static default route
1024 because of lack of function to originate default in ospf6d; sorry
1025 yasu
1026 if (mask < 13)
1027 return partly_match;
1028*/
1029
1030 return exact_match;
1031}
1032
paul22e0a9e2003-07-11 17:55:46 +00001033#endif /* HAVE_IPV6 */
1034
paul718e3742002-12-13 20:15:29 +00001035#define DECIMAL_STRLEN_MAX 10
1036
1037int
hasso8c328f12004-10-05 21:01:23 +00001038cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001039{
1040 char *p;
1041 char buf[DECIMAL_STRLEN_MAX + 1];
1042 char *endptr = NULL;
1043 unsigned long min, max, val;
1044
1045 if (str == NULL)
1046 return 1;
1047
1048 val = strtoul (str, &endptr, 10);
1049 if (*endptr != '\0')
1050 return 0;
1051
1052 range++;
1053 p = strchr (range, '-');
1054 if (p == NULL)
1055 return 0;
1056 if (p - range > DECIMAL_STRLEN_MAX)
1057 return 0;
1058 strncpy (buf, range, p - range);
1059 buf[p - range] = '\0';
1060 min = strtoul (buf, &endptr, 10);
1061 if (*endptr != '\0')
1062 return 0;
1063
1064 range = p + 1;
1065 p = strchr (range, '>');
1066 if (p == NULL)
1067 return 0;
1068 if (p - range > DECIMAL_STRLEN_MAX)
1069 return 0;
1070 strncpy (buf, range, p - range);
1071 buf[p - range] = '\0';
1072 max = strtoul (buf, &endptr, 10);
1073 if (*endptr != '\0')
1074 return 0;
1075
1076 if (val < min || val > max)
1077 return 0;
1078
1079 return 1;
1080}
1081
1082/* Make completion match and return match type flag. */
1083enum match_type
hasso8c328f12004-10-05 21:01:23 +00001084cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001085{
hasso8c328f12004-10-05 21:01:23 +00001086 unsigned int i;
1087 const char *str;
paul718e3742002-12-13 20:15:29 +00001088 struct cmd_element *cmd_element;
1089 enum match_type match_type;
1090 vector descvec;
1091 struct desc *desc;
1092
1093 match_type = no_match;
1094
1095 /* If command and cmd_element string does not match set NULL to vector */
1096 for (i = 0; i < vector_max (v); i++)
1097 if ((cmd_element = vector_slot (v, i)) != NULL)
1098 {
1099 if (index >= vector_max (cmd_element->strvec))
1100 vector_slot (v, i) = NULL;
1101 else
1102 {
hasso8c328f12004-10-05 21:01:23 +00001103 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001104 int matched = 0;
1105
1106 descvec = vector_slot (cmd_element->strvec, index);
1107
1108 for (j = 0; j < vector_max (descvec); j++)
1109 {
1110 desc = vector_slot (descvec, j);
1111 str = desc->cmd;
1112
1113 if (CMD_VARARG (str))
1114 {
1115 if (match_type < vararg_match)
1116 match_type = vararg_match;
1117 matched++;
1118 }
1119 else if (CMD_RANGE (str))
1120 {
1121 if (cmd_range_match (str, command))
1122 {
1123 if (match_type < range_match)
1124 match_type = range_match;
1125
1126 matched++;
1127 }
1128 }
paul22e0a9e2003-07-11 17:55:46 +00001129#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001130 else if (CMD_IPV6 (str))
1131 {
1132 if (cmd_ipv6_match (command))
1133 {
1134 if (match_type < ipv6_match)
1135 match_type = ipv6_match;
1136
1137 matched++;
1138 }
1139 }
1140 else if (CMD_IPV6_PREFIX (str))
1141 {
1142 if (cmd_ipv6_prefix_match (command))
1143 {
1144 if (match_type < ipv6_prefix_match)
1145 match_type = ipv6_prefix_match;
1146
1147 matched++;
1148 }
1149 }
paul22e0a9e2003-07-11 17:55:46 +00001150#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001151 else if (CMD_IPV4 (str))
1152 {
1153 if (cmd_ipv4_match (command))
1154 {
1155 if (match_type < ipv4_match)
1156 match_type = ipv4_match;
1157
1158 matched++;
1159 }
1160 }
1161 else if (CMD_IPV4_PREFIX (str))
1162 {
1163 if (cmd_ipv4_prefix_match (command))
1164 {
1165 if (match_type < ipv4_prefix_match)
1166 match_type = ipv4_prefix_match;
1167 matched++;
1168 }
1169 }
1170 else
1171 /* Check is this point's argument optional ? */
1172 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1173 {
1174 if (match_type < extend_match)
1175 match_type = extend_match;
1176 matched++;
1177 }
1178 else if (strncmp (command, str, strlen (command)) == 0)
1179 {
1180 if (strcmp (command, str) == 0)
1181 match_type = exact_match;
1182 else
1183 {
1184 if (match_type < partly_match)
1185 match_type = partly_match;
1186 }
1187 matched++;
1188 }
1189 }
1190 if (! matched)
1191 vector_slot (v, i) = NULL;
1192 }
1193 }
1194 return match_type;
1195}
1196
1197/* Filter vector by command character with index. */
1198enum match_type
hasso8c328f12004-10-05 21:01:23 +00001199cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001200{
hasso8c328f12004-10-05 21:01:23 +00001201 unsigned int i;
1202 const char *str;
paul718e3742002-12-13 20:15:29 +00001203 struct cmd_element *cmd_element;
1204 enum match_type match_type;
1205 vector descvec;
1206 struct desc *desc;
1207
1208 match_type = no_match;
1209
1210 /* If command and cmd_element string does not match set NULL to vector */
1211 for (i = 0; i < vector_max (v); i++)
1212 if ((cmd_element = vector_slot (v, i)) != NULL)
1213 {
1214 /* If given index is bigger than max string vector of command,
1215 set NULL*/
1216 if (index >= vector_max (cmd_element->strvec))
1217 vector_slot (v, i) = NULL;
1218 else
1219 {
hasso8c328f12004-10-05 21:01:23 +00001220 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001221 int matched = 0;
1222
1223 descvec = vector_slot (cmd_element->strvec, index);
1224
1225 for (j = 0; j < vector_max (descvec); j++)
1226 {
1227 desc = vector_slot (descvec, j);
1228 str = desc->cmd;
1229
1230 if (CMD_VARARG (str))
1231 {
1232 if (match_type < vararg_match)
1233 match_type = vararg_match;
1234 matched++;
1235 }
1236 else if (CMD_RANGE (str))
1237 {
1238 if (cmd_range_match (str, command))
1239 {
1240 if (match_type < range_match)
1241 match_type = range_match;
1242 matched++;
1243 }
1244 }
paul22e0a9e2003-07-11 17:55:46 +00001245#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001246 else if (CMD_IPV6 (str))
1247 {
1248 if (cmd_ipv6_match (command) == exact_match)
1249 {
1250 if (match_type < ipv6_match)
1251 match_type = ipv6_match;
1252 matched++;
1253 }
1254 }
1255 else if (CMD_IPV6_PREFIX (str))
1256 {
1257 if (cmd_ipv6_prefix_match (command) == exact_match)
1258 {
1259 if (match_type < ipv6_prefix_match)
1260 match_type = ipv6_prefix_match;
1261 matched++;
1262 }
1263 }
paul22e0a9e2003-07-11 17:55:46 +00001264#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001265 else if (CMD_IPV4 (str))
1266 {
1267 if (cmd_ipv4_match (command) == exact_match)
1268 {
1269 if (match_type < ipv4_match)
1270 match_type = ipv4_match;
1271 matched++;
1272 }
1273 }
1274 else if (CMD_IPV4_PREFIX (str))
1275 {
1276 if (cmd_ipv4_prefix_match (command) == exact_match)
1277 {
1278 if (match_type < ipv4_prefix_match)
1279 match_type = ipv4_prefix_match;
1280 matched++;
1281 }
1282 }
1283 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1284 {
1285 if (match_type < extend_match)
1286 match_type = extend_match;
1287 matched++;
1288 }
1289 else
1290 {
1291 if (strcmp (command, str) == 0)
1292 {
1293 match_type = exact_match;
1294 matched++;
1295 }
1296 }
1297 }
1298 if (! matched)
1299 vector_slot (v, i) = NULL;
1300 }
1301 }
1302 return match_type;
1303}
1304
1305/* Check ambiguous match */
1306int
1307is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1308{
hasso8c328f12004-10-05 21:01:23 +00001309 unsigned int i;
1310 unsigned int j;
1311 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001312 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001313 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001314 vector descvec;
1315 struct desc *desc;
1316
1317 for (i = 0; i < vector_max (v); i++)
1318 if ((cmd_element = vector_slot (v, i)) != NULL)
1319 {
1320 int match = 0;
1321
1322 descvec = vector_slot (cmd_element->strvec, index);
1323
1324 for (j = 0; j < vector_max (descvec); j++)
1325 {
1326 enum match_type ret;
1327
1328 desc = vector_slot (descvec, j);
1329 str = desc->cmd;
1330
1331 switch (type)
1332 {
1333 case exact_match:
1334 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1335 && strcmp (command, str) == 0)
1336 match++;
1337 break;
1338 case partly_match:
1339 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1340 && strncmp (command, str, strlen (command)) == 0)
1341 {
1342 if (matched && strcmp (matched, str) != 0)
1343 return 1; /* There is ambiguous match. */
1344 else
1345 matched = str;
1346 match++;
1347 }
1348 break;
1349 case range_match:
1350 if (cmd_range_match (str, command))
1351 {
1352 if (matched && strcmp (matched, str) != 0)
1353 return 1;
1354 else
1355 matched = str;
1356 match++;
1357 }
1358 break;
paul22e0a9e2003-07-11 17:55:46 +00001359#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001360 case ipv6_match:
1361 if (CMD_IPV6 (str))
1362 match++;
1363 break;
1364 case ipv6_prefix_match:
1365 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1366 {
1367 if (ret == partly_match)
1368 return 2; /* There is incomplete match. */
1369
1370 match++;
1371 }
1372 break;
paul22e0a9e2003-07-11 17:55:46 +00001373#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001374 case ipv4_match:
1375 if (CMD_IPV4 (str))
1376 match++;
1377 break;
1378 case ipv4_prefix_match:
1379 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1380 {
1381 if (ret == partly_match)
1382 return 2; /* There is incomplete match. */
1383
1384 match++;
1385 }
1386 break;
1387 case extend_match:
1388 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1389 match++;
1390 break;
1391 case no_match:
1392 default:
1393 break;
1394 }
1395 }
1396 if (! match)
1397 vector_slot (v, i) = NULL;
1398 }
1399 return 0;
1400}
1401
1402/* If src matches dst return dst string, otherwise return NULL */
hasso8c328f12004-10-05 21:01:23 +00001403const char *
1404cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001405{
1406 /* Skip variable arguments. */
1407 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1408 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1409 return NULL;
1410
1411 /* In case of 'command \t', given src is NULL string. */
1412 if (src == NULL)
1413 return dst;
1414
1415 /* Matched with input string. */
1416 if (strncmp (src, dst, strlen (src)) == 0)
1417 return dst;
1418
1419 return NULL;
1420}
1421
1422/* If src matches dst return dst string, otherwise return NULL */
1423/* This version will return the dst string always if it is
1424 CMD_VARIABLE for '?' key processing */
hasso8c328f12004-10-05 21:01:23 +00001425const char *
1426cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001427{
1428 if (CMD_VARARG (dst))
1429 return dst;
1430
1431 if (CMD_RANGE (dst))
1432 {
1433 if (cmd_range_match (dst, src))
1434 return dst;
1435 else
1436 return NULL;
1437 }
1438
paul22e0a9e2003-07-11 17:55:46 +00001439#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001440 if (CMD_IPV6 (dst))
1441 {
1442 if (cmd_ipv6_match (src))
1443 return dst;
1444 else
1445 return NULL;
1446 }
1447
1448 if (CMD_IPV6_PREFIX (dst))
1449 {
1450 if (cmd_ipv6_prefix_match (src))
1451 return dst;
1452 else
1453 return NULL;
1454 }
paul22e0a9e2003-07-11 17:55:46 +00001455#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001456
1457 if (CMD_IPV4 (dst))
1458 {
1459 if (cmd_ipv4_match (src))
1460 return dst;
1461 else
1462 return NULL;
1463 }
1464
1465 if (CMD_IPV4_PREFIX (dst))
1466 {
1467 if (cmd_ipv4_prefix_match (src))
1468 return dst;
1469 else
1470 return NULL;
1471 }
1472
1473 /* Optional or variable commands always match on '?' */
1474 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1475 return dst;
1476
1477 /* In case of 'command \t', given src is NULL string. */
1478 if (src == NULL)
1479 return dst;
1480
1481 if (strncmp (src, dst, strlen (src)) == 0)
1482 return dst;
1483 else
1484 return NULL;
1485}
1486
1487/* Check same string element existence. If it isn't there return
1488 1. */
1489int
hasso8c328f12004-10-05 21:01:23 +00001490cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001491{
hasso8c328f12004-10-05 21:01:23 +00001492 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001493 char *match;
1494
1495 for (i = 0; i < vector_max (v); i++)
1496 if ((match = vector_slot (v, i)) != NULL)
1497 if (strcmp (match, str) == 0)
1498 return 0;
1499 return 1;
1500}
1501
1502/* Compare string to description vector. If there is same string
1503 return 1 else return 0. */
1504int
hasso8c328f12004-10-05 21:01:23 +00001505desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001506{
hasso8c328f12004-10-05 21:01:23 +00001507 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001508 struct desc *desc;
1509
1510 for (i = 0; i < vector_max (v); i++)
1511 if ((desc = vector_slot (v, i)) != NULL)
1512 if (strcmp (desc->cmd, str) == 0)
1513 return 1;
1514 return 0;
1515}
1516
paulb92938a2002-12-13 21:20:42 +00001517int
1518cmd_try_do_shortcut (enum node_type node, char* first_word) {
1519 if ( first_word != NULL &&
1520 node != AUTH_NODE &&
1521 node != VIEW_NODE &&
1522 node != AUTH_ENABLE_NODE &&
1523 node != ENABLE_NODE &&
1524 0 == strcmp( "do", first_word ) )
1525 return 1;
1526 return 0;
1527}
1528
paul718e3742002-12-13 20:15:29 +00001529/* '?' describe command support. */
1530vector
paulb92938a2002-12-13 21:20:42 +00001531cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001532{
hasso8c328f12004-10-05 21:01:23 +00001533 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001534 vector cmd_vector;
1535#define INIT_MATCHVEC_SIZE 10
1536 vector matchvec;
1537 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001538 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001539 int ret;
1540 enum match_type match;
1541 char *command;
paul718e3742002-12-13 20:15:29 +00001542 static struct desc desc_cr = { "<cr>", "" };
1543
1544 /* Set index. */
1545 index = vector_max (vline) - 1;
1546
1547 /* Make copy vector of current node's command vector. */
1548 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1549
1550 /* Prepare match vector */
1551 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1552
1553 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001554 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001555 for (i = 0; i < index; i++)
1556 {
paul718e3742002-12-13 20:15:29 +00001557 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00001558 match = cmd_filter_by_completion (command, cmd_vector, i);
1559
1560 if (match == vararg_match)
1561 {
1562 struct cmd_element *cmd_element;
1563 vector descvec;
hasso8c328f12004-10-05 21:01:23 +00001564 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001565
1566 for (j = 0; j < vector_max (cmd_vector); j++)
1567 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1568 {
1569 descvec = vector_slot (cmd_element->strvec,
1570 vector_max (cmd_element->strvec) - 1);
1571 for (k = 0; k < vector_max (descvec); k++)
1572 {
1573 struct desc *desc = vector_slot (descvec, k);
1574 vector_set (matchvec, desc);
1575 }
1576 }
1577
1578 vector_set (matchvec, &desc_cr);
paul718e3742002-12-13 20:15:29 +00001579 vector_free (cmd_vector);
1580
1581 return matchvec;
1582 }
1583
1584 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1585 {
1586 vector_free (cmd_vector);
1587 *status = CMD_ERR_AMBIGUOUS;
1588 return NULL;
1589 }
1590 else if (ret == 2)
1591 {
1592 vector_free (cmd_vector);
1593 *status = CMD_ERR_NO_MATCH;
1594 return NULL;
1595 }
1596 }
1597
1598 /* Prepare match vector */
1599 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1600
paul54aba542003-08-21 20:28:24 +00001601 /* Make sure that cmd_vector is filtered based on current word */
1602 command = vector_slot (vline, index);
1603 if (command)
1604 match = cmd_filter_by_completion (command, cmd_vector, index);
1605
paul718e3742002-12-13 20:15:29 +00001606 /* Make description vector. */
1607 for (i = 0; i < vector_max (cmd_vector); i++)
1608 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1609 {
hasso8c328f12004-10-05 21:01:23 +00001610 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001611 vector strvec = cmd_element->strvec;
1612
paul54aba542003-08-21 20:28:24 +00001613 /* if command is NULL, index may be equal to vector_max */
1614 if (command && index >= vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001615 vector_slot (cmd_vector, i) = NULL;
1616 else
1617 {
paul54aba542003-08-21 20:28:24 +00001618 /* Check if command is completed. */
1619 if (command == NULL && index == vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001620 {
1621 string = "<cr>";
1622 if (! desc_unique_string (matchvec, string))
1623 vector_set (matchvec, &desc_cr);
1624 }
1625 else
1626 {
hasso8c328f12004-10-05 21:01:23 +00001627 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001628 vector descvec = vector_slot (strvec, index);
1629 struct desc *desc;
1630
1631 for (j = 0; j < vector_max (descvec); j++)
1632 {
1633 desc = vector_slot (descvec, j);
paul54aba542003-08-21 20:28:24 +00001634 string = cmd_entry_function_desc (command, desc->cmd);
paul718e3742002-12-13 20:15:29 +00001635 if (string)
1636 {
1637 /* Uniqueness check */
1638 if (! desc_unique_string (matchvec, string))
1639 vector_set (matchvec, desc);
1640 }
1641 }
1642 }
1643 }
1644 }
1645 vector_free (cmd_vector);
1646
1647 if (vector_slot (matchvec, 0) == NULL)
1648 {
1649 vector_free (matchvec);
1650 *status= CMD_ERR_NO_MATCH;
1651 }
1652 else
1653 *status = CMD_SUCCESS;
1654
1655 return matchvec;
1656}
1657
paulb92938a2002-12-13 21:20:42 +00001658vector
1659cmd_describe_command (vector vline, struct vty *vty, int *status)
1660{
1661 vector ret;
1662
1663 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1664 {
1665 enum node_type onode;
1666 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001667 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001668
1669 onode = vty->node;
1670 vty->node = ENABLE_NODE;
1671 /* We can try it on enable node, cos' the vty is authenticated */
1672
1673 shifted_vline = vector_init (vector_count(vline));
1674 /* use memcpy? */
1675 for (index = 1; index < vector_max (vline); index++)
1676 {
1677 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1678 }
1679
1680 ret = cmd_describe_command_real (shifted_vline, vty, status);
1681
1682 vector_free(shifted_vline);
1683 vty->node = onode;
1684 return ret;
1685 }
1686
1687
1688 return cmd_describe_command_real (vline, vty, status);
1689}
1690
1691
paul718e3742002-12-13 20:15:29 +00001692/* Check LCD of matched command. */
1693int
1694cmd_lcd (char **matched)
1695{
1696 int i;
1697 int j;
1698 int lcd = -1;
1699 char *s1, *s2;
1700 char c1, c2;
1701
1702 if (matched[0] == NULL || matched[1] == NULL)
1703 return 0;
1704
1705 for (i = 1; matched[i] != NULL; i++)
1706 {
1707 s1 = matched[i - 1];
1708 s2 = matched[i];
1709
1710 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1711 if (c1 != c2)
1712 break;
1713
1714 if (lcd < 0)
1715 lcd = j;
1716 else
1717 {
1718 if (lcd > j)
1719 lcd = j;
1720 }
1721 }
1722 return lcd;
1723}
1724
1725/* Command line completion support. */
1726char **
paulb92938a2002-12-13 21:20:42 +00001727cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001728{
hasso8c328f12004-10-05 21:01:23 +00001729 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001730 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1731#define INIT_MATCHVEC_SIZE 10
1732 vector matchvec;
1733 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001734 unsigned int index = vector_max (vline) - 1;
paul718e3742002-12-13 20:15:29 +00001735 char **match_str;
1736 struct desc *desc;
1737 vector descvec;
1738 char *command;
1739 int lcd;
1740
1741 /* First, filter by preceeding command string */
1742 for (i = 0; i < index; i++)
1743 {
1744 enum match_type match;
1745 int ret;
1746
1747 command = vector_slot (vline, i);
1748
1749 /* First try completion match, if there is exactly match return 1 */
1750 match = cmd_filter_by_completion (command, cmd_vector, i);
1751
1752 /* If there is exact match then filter ambiguous match else check
1753 ambiguousness. */
1754 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1755 {
1756 vector_free (cmd_vector);
1757 *status = CMD_ERR_AMBIGUOUS;
1758 return NULL;
1759 }
1760 /*
1761 else if (ret == 2)
1762 {
1763 vector_free (cmd_vector);
1764 *status = CMD_ERR_NO_MATCH;
1765 return NULL;
1766 }
1767 */
1768 }
1769
1770 /* Prepare match vector. */
1771 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1772
1773 /* Now we got into completion */
1774 for (i = 0; i < vector_max (cmd_vector); i++)
1775 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1776 {
hasso8c328f12004-10-05 21:01:23 +00001777 const char *string;
paul718e3742002-12-13 20:15:29 +00001778 vector strvec = cmd_element->strvec;
1779
1780 /* Check field length */
1781 if (index >= vector_max (strvec))
1782 vector_slot (cmd_vector, i) = NULL;
1783 else
1784 {
hasso8c328f12004-10-05 21:01:23 +00001785 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001786
1787 descvec = vector_slot (strvec, index);
1788 for (j = 0; j < vector_max (descvec); j++)
1789 {
1790 desc = vector_slot (descvec, j);
1791
1792 if ((string = cmd_entry_function (vector_slot (vline, index),
1793 desc->cmd)))
1794 if (cmd_unique_string (matchvec, string))
1795 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1796 }
1797 }
1798 }
1799
1800 /* We don't need cmd_vector any more. */
1801 vector_free (cmd_vector);
1802
1803 /* No matched command */
1804 if (vector_slot (matchvec, 0) == NULL)
1805 {
1806 vector_free (matchvec);
1807
1808 /* In case of 'command \t' pattern. Do you need '?' command at
1809 the end of the line. */
1810 if (vector_slot (vline, index) == '\0')
1811 *status = CMD_ERR_NOTHING_TODO;
1812 else
1813 *status = CMD_ERR_NO_MATCH;
1814 return NULL;
1815 }
1816
1817 /* Only one matched */
1818 if (vector_slot (matchvec, 1) == NULL)
1819 {
1820 match_str = (char **) matchvec->index;
1821 vector_only_wrapper_free (matchvec);
1822 *status = CMD_COMPLETE_FULL_MATCH;
1823 return match_str;
1824 }
1825 /* Make it sure last element is NULL. */
1826 vector_set (matchvec, NULL);
1827
1828 /* Check LCD of matched strings. */
1829 if (vector_slot (vline, index) != NULL)
1830 {
1831 lcd = cmd_lcd ((char **) matchvec->index);
1832
1833 if (lcd)
1834 {
1835 int len = strlen (vector_slot (vline, index));
1836
1837 if (len < lcd)
1838 {
1839 char *lcdstr;
1840
1841 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1842 memcpy (lcdstr, matchvec->index[0], lcd);
1843 lcdstr[lcd] = '\0';
1844
1845 /* match_str = (char **) &lcdstr; */
1846
1847 /* Free matchvec. */
1848 for (i = 0; i < vector_max (matchvec); i++)
1849 {
1850 if (vector_slot (matchvec, i))
1851 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1852 }
1853 vector_free (matchvec);
1854
1855 /* Make new matchvec. */
1856 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1857 vector_set (matchvec, lcdstr);
1858 match_str = (char **) matchvec->index;
1859 vector_only_wrapper_free (matchvec);
1860
1861 *status = CMD_COMPLETE_MATCH;
1862 return match_str;
1863 }
1864 }
1865 }
1866
1867 match_str = (char **) matchvec->index;
1868 vector_only_wrapper_free (matchvec);
1869 *status = CMD_COMPLETE_LIST_MATCH;
1870 return match_str;
1871}
1872
paulb92938a2002-12-13 21:20:42 +00001873char **
paul9ab68122003-01-18 01:16:20 +00001874cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001875{
1876 char **ret;
1877
1878 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1879 {
1880 enum node_type onode;
1881 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001882 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001883
1884 onode = vty->node;
1885 vty->node = ENABLE_NODE;
1886 /* We can try it on enable node, cos' the vty is authenticated */
1887
1888 shifted_vline = vector_init (vector_count(vline));
1889 /* use memcpy? */
1890 for (index = 1; index < vector_max (vline); index++)
1891 {
1892 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1893 }
1894
1895 ret = cmd_complete_command_real (shifted_vline, vty, status);
1896
1897 vector_free(shifted_vline);
1898 vty->node = onode;
1899 return ret;
1900 }
1901
1902
1903 return cmd_complete_command_real (vline, vty, status);
1904}
1905
1906/* return parent node */
1907/* MUST eventually converge on CONFIG_NODE */
1908enum node_type node_parent ( enum node_type node )
1909{
1910 enum node_type ret;
1911
paul9ab68122003-01-18 01:16:20 +00001912 assert (node > CONFIG_NODE);
1913
1914 switch (node)
1915 {
1916 case BGP_VPNV4_NODE:
1917 case BGP_IPV4_NODE:
1918 case BGP_IPV4M_NODE:
1919 case BGP_IPV6_NODE:
1920 ret = BGP_NODE;
1921 break;
1922 case KEYCHAIN_KEY_NODE:
1923 ret = KEYCHAIN_NODE;
1924 break;
1925 default:
1926 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001927 }
1928
1929 return ret;
1930}
1931
paul718e3742002-12-13 20:15:29 +00001932/* Execute command by argument vline vector. */
1933int
paulb92938a2002-12-13 21:20:42 +00001934cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001935{
hasso8c328f12004-10-05 21:01:23 +00001936 unsigned int i;
1937 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001938 vector cmd_vector;
1939 struct cmd_element *cmd_element;
1940 struct cmd_element *matched_element;
1941 unsigned int matched_count, incomplete_count;
1942 int argc;
paul9035efa2004-10-10 11:56:56 +00001943 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001944 enum match_type match = 0;
1945 int varflag;
1946 char *command;
1947
1948 /* Make copy of command elements. */
1949 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1950
1951 for (index = 0; index < vector_max (vline); index++)
1952 {
1953 int ret;
1954
1955 command = vector_slot (vline, index);
1956
1957 match = cmd_filter_by_completion (command, cmd_vector, index);
1958
1959 if (match == vararg_match)
1960 break;
1961
1962 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1963
1964 if (ret == 1)
1965 {
1966 vector_free (cmd_vector);
1967 return CMD_ERR_AMBIGUOUS;
1968 }
1969 else if (ret == 2)
1970 {
1971 vector_free (cmd_vector);
1972 return CMD_ERR_NO_MATCH;
1973 }
1974 }
1975
1976 /* Check matched count. */
1977 matched_element = NULL;
1978 matched_count = 0;
1979 incomplete_count = 0;
1980
1981 for (i = 0; i < vector_max (cmd_vector); i++)
1982 if (vector_slot (cmd_vector,i) != NULL)
1983 {
1984 cmd_element = vector_slot (cmd_vector,i);
1985
1986 if (match == vararg_match || index >= cmd_element->cmdsize)
1987 {
1988 matched_element = cmd_element;
1989#if 0
1990 printf ("DEBUG: %s\n", cmd_element->string);
1991#endif
1992 matched_count++;
1993 }
1994 else
1995 {
1996 incomplete_count++;
1997 }
1998 }
1999
2000 /* Finish of using cmd_vector. */
2001 vector_free (cmd_vector);
2002
2003 /* To execute command, matched_count must be 1.*/
2004 if (matched_count == 0)
2005 {
2006 if (incomplete_count)
2007 return CMD_ERR_INCOMPLETE;
2008 else
2009 return CMD_ERR_NO_MATCH;
2010 }
2011
2012 if (matched_count > 1)
2013 return CMD_ERR_AMBIGUOUS;
2014
2015 /* Argument treatment */
2016 varflag = 0;
2017 argc = 0;
2018
2019 for (i = 0; i < vector_max (vline); i++)
2020 {
2021 if (varflag)
2022 argv[argc++] = vector_slot (vline, i);
2023 else
2024 {
2025 vector descvec = vector_slot (matched_element->strvec, i);
2026
2027 if (vector_max (descvec) == 1)
2028 {
2029 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002030
hasso8c328f12004-10-05 21:01:23 +00002031 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002032 varflag = 1;
2033
hasso8c328f12004-10-05 21:01:23 +00002034 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002035 argv[argc++] = vector_slot (vline, i);
2036 }
2037 else
2038 argv[argc++] = vector_slot (vline, i);
2039 }
2040
2041 if (argc >= CMD_ARGC_MAX)
2042 return CMD_ERR_EXEED_ARGC_MAX;
2043 }
2044
2045 /* For vtysh execution. */
2046 if (cmd)
2047 *cmd = matched_element;
2048
2049 if (matched_element->daemon)
2050 return CMD_SUCCESS_DAEMON;
2051
2052 /* Execute matched command. */
2053 return (*matched_element->func) (matched_element, vty, argc, argv);
2054}
2055
paulb92938a2002-12-13 21:20:42 +00002056
2057int
2058cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
paul9ab68122003-01-18 01:16:20 +00002059 int ret, saved_ret, tried = 0;
2060 enum node_type onode, try_node;
2061
2062 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002063
2064 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2065 {
2066 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002067 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002068
2069 vty->node = ENABLE_NODE;
2070 /* We can try it on enable node, cos' the vty is authenticated */
2071
2072 shifted_vline = vector_init (vector_count(vline));
2073 /* use memcpy? */
2074 for (index = 1; index < vector_max (vline); index++)
2075 {
2076 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2077 }
2078
2079 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2080
2081 vector_free(shifted_vline);
2082 vty->node = onode;
2083 return ret;
2084 }
2085
2086
paul9ab68122003-01-18 01:16:20 +00002087 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002088
2089 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002090 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002091 && vty->node > CONFIG_NODE )
2092 {
paul9ab68122003-01-18 01:16:20 +00002093 try_node = node_parent(try_node);
2094 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002095 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002096 tried = 1;
2097 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002098 {
paul9ab68122003-01-18 01:16:20 +00002099 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002100 return ret;
2101 }
paulb92938a2002-12-13 21:20:42 +00002102 }
paul9ab68122003-01-18 01:16:20 +00002103 /* no command succeeded, reset the vty to the original node and
2104 return the error for this node */
2105 if ( tried )
2106 vty->node = onode;
2107 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002108}
2109
paul718e3742002-12-13 20:15:29 +00002110/* Execute command by argument readline. */
2111int
2112cmd_execute_command_strict (vector vline, struct vty *vty,
2113 struct cmd_element **cmd)
2114{
hasso8c328f12004-10-05 21:01:23 +00002115 unsigned int i;
2116 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002117 vector cmd_vector;
2118 struct cmd_element *cmd_element;
2119 struct cmd_element *matched_element;
2120 unsigned int matched_count, incomplete_count;
2121 int argc;
paul9035efa2004-10-10 11:56:56 +00002122 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002123 int varflag;
2124 enum match_type match = 0;
2125 char *command;
2126
2127 /* Make copy of command element */
2128 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2129
2130 for (index = 0; index < vector_max (vline); index++)
2131 {
2132 int ret;
2133
2134 command = vector_slot (vline, index);
2135
2136 match = cmd_filter_by_string (vector_slot (vline, index),
2137 cmd_vector, index);
2138
2139 /* If command meets '.VARARG' then finish matching. */
2140 if (match == vararg_match)
2141 break;
2142
2143 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2144 if (ret == 1)
2145 {
2146 vector_free (cmd_vector);
2147 return CMD_ERR_AMBIGUOUS;
2148 }
2149 if (ret == 2)
2150 {
2151 vector_free (cmd_vector);
2152 return CMD_ERR_NO_MATCH;
2153 }
2154 }
2155
2156 /* Check matched count. */
2157 matched_element = NULL;
2158 matched_count = 0;
2159 incomplete_count = 0;
2160 for (i = 0; i < vector_max (cmd_vector); i++)
2161 if (vector_slot (cmd_vector,i) != NULL)
2162 {
2163 cmd_element = vector_slot (cmd_vector,i);
2164
2165 if (match == vararg_match || index >= cmd_element->cmdsize)
2166 {
2167 matched_element = cmd_element;
2168 matched_count++;
2169 }
2170 else
2171 incomplete_count++;
2172 }
2173
2174 /* Finish of using cmd_vector. */
2175 vector_free (cmd_vector);
2176
2177 /* To execute command, matched_count must be 1.*/
2178 if (matched_count == 0)
2179 {
2180 if (incomplete_count)
2181 return CMD_ERR_INCOMPLETE;
2182 else
2183 return CMD_ERR_NO_MATCH;
2184 }
2185
2186 if (matched_count > 1)
2187 return CMD_ERR_AMBIGUOUS;
2188
2189 /* Argument treatment */
2190 varflag = 0;
2191 argc = 0;
2192
2193 for (i = 0; i < vector_max (vline); i++)
2194 {
2195 if (varflag)
2196 argv[argc++] = vector_slot (vline, i);
2197 else
2198 {
2199 vector descvec = vector_slot (matched_element->strvec, i);
2200
2201 if (vector_max (descvec) == 1)
2202 {
2203 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002204
hasso8c328f12004-10-05 21:01:23 +00002205 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002206 varflag = 1;
2207
hasso8c328f12004-10-05 21:01:23 +00002208 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002209 argv[argc++] = vector_slot (vline, i);
2210 }
2211 else
2212 argv[argc++] = vector_slot (vline, i);
2213 }
2214
2215 if (argc >= CMD_ARGC_MAX)
2216 return CMD_ERR_EXEED_ARGC_MAX;
2217 }
2218
2219 /* For vtysh execution. */
2220 if (cmd)
2221 *cmd = matched_element;
2222
2223 if (matched_element->daemon)
2224 return CMD_SUCCESS_DAEMON;
2225
2226 /* Now execute matched command */
2227 return (*matched_element->func) (matched_element, vty, argc, argv);
2228}
2229
2230/* Configration make from file. */
2231int
2232config_from_file (struct vty *vty, FILE *fp)
2233{
2234 int ret;
2235 vector vline;
2236
2237 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2238 {
2239 vline = cmd_make_strvec (vty->buf);
2240
2241 /* In case of comment line */
2242 if (vline == NULL)
2243 continue;
2244 /* Execute configuration command : this is strict match */
2245 ret = cmd_execute_command_strict (vline, vty, NULL);
2246
2247 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002248 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002249 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2250 {
paulb92938a2002-12-13 21:20:42 +00002251 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002252 ret = cmd_execute_command_strict (vline, vty, NULL);
2253 }
paul9ab68122003-01-18 01:16:20 +00002254
paul718e3742002-12-13 20:15:29 +00002255 cmd_free_strvec (vline);
2256
hassoddd85ed2004-10-13 08:18:07 +00002257 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2258 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002259 return ret;
2260 }
2261 return CMD_SUCCESS;
2262}
2263
2264/* Configration from terminal */
2265DEFUN (config_terminal,
2266 config_terminal_cmd,
2267 "configure terminal",
2268 "Configuration from vty interface\n"
2269 "Configuration terminal\n")
2270{
2271 if (vty_config_lock (vty))
2272 vty->node = CONFIG_NODE;
2273 else
2274 {
2275 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2276 return CMD_WARNING;
2277 }
2278 return CMD_SUCCESS;
2279}
2280
2281/* Enable command */
2282DEFUN (enable,
2283 config_enable_cmd,
2284 "enable",
2285 "Turn on privileged mode command\n")
2286{
2287 /* If enable password is NULL, change to ENABLE_NODE */
2288 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2289 vty->type == VTY_SHELL_SERV)
2290 vty->node = ENABLE_NODE;
2291 else
2292 vty->node = AUTH_ENABLE_NODE;
2293
2294 return CMD_SUCCESS;
2295}
2296
2297/* Disable command */
2298DEFUN (disable,
2299 config_disable_cmd,
2300 "disable",
2301 "Turn off privileged mode command\n")
2302{
2303 if (vty->node == ENABLE_NODE)
2304 vty->node = VIEW_NODE;
2305 return CMD_SUCCESS;
2306}
2307
2308/* Down vty node level. */
2309DEFUN (config_exit,
2310 config_exit_cmd,
2311 "exit",
2312 "Exit current mode and down to previous mode\n")
2313{
2314 switch (vty->node)
2315 {
2316 case VIEW_NODE:
2317 case ENABLE_NODE:
2318 if (vty_shell (vty))
2319 exit (0);
2320 else
2321 vty->status = VTY_CLOSE;
2322 break;
2323 case CONFIG_NODE:
2324 vty->node = ENABLE_NODE;
2325 vty_config_unlock (vty);
2326 break;
2327 case INTERFACE_NODE:
2328 case ZEBRA_NODE:
2329 case BGP_NODE:
2330 case RIP_NODE:
2331 case RIPNG_NODE:
2332 case OSPF_NODE:
2333 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002334 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002335 case KEYCHAIN_NODE:
2336 case MASC_NODE:
2337 case RMAP_NODE:
2338 case VTY_NODE:
2339 vty->node = CONFIG_NODE;
2340 break;
2341 case BGP_VPNV4_NODE:
2342 case BGP_IPV4_NODE:
2343 case BGP_IPV4M_NODE:
2344 case BGP_IPV6_NODE:
2345 vty->node = BGP_NODE;
2346 break;
2347 case KEYCHAIN_KEY_NODE:
2348 vty->node = KEYCHAIN_NODE;
2349 break;
2350 default:
2351 break;
2352 }
2353 return CMD_SUCCESS;
2354}
2355
2356/* quit is alias of exit. */
2357ALIAS (config_exit,
2358 config_quit_cmd,
2359 "quit",
2360 "Exit current mode and down to previous mode\n")
2361
2362/* End of configuration. */
2363DEFUN (config_end,
2364 config_end_cmd,
2365 "end",
2366 "End current mode and change to enable mode.")
2367{
2368 switch (vty->node)
2369 {
2370 case VIEW_NODE:
2371 case ENABLE_NODE:
2372 /* Nothing to do. */
2373 break;
2374 case CONFIG_NODE:
2375 case INTERFACE_NODE:
2376 case ZEBRA_NODE:
2377 case RIP_NODE:
2378 case RIPNG_NODE:
2379 case BGP_NODE:
2380 case BGP_VPNV4_NODE:
2381 case BGP_IPV4_NODE:
2382 case BGP_IPV4M_NODE:
2383 case BGP_IPV6_NODE:
2384 case RMAP_NODE:
2385 case OSPF_NODE:
2386 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002387 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002388 case KEYCHAIN_NODE:
2389 case KEYCHAIN_KEY_NODE:
2390 case MASC_NODE:
2391 case VTY_NODE:
2392 vty_config_unlock (vty);
2393 vty->node = ENABLE_NODE;
2394 break;
2395 default:
2396 break;
2397 }
2398 return CMD_SUCCESS;
2399}
2400
2401/* Show version. */
2402DEFUN (show_version,
2403 show_version_cmd,
2404 "show version",
2405 SHOW_STR
2406 "Displays zebra version\n")
2407{
hasso6590f2c2004-10-19 20:40:08 +00002408 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name, VTY_NEWLINE);
2409 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002410
2411 return CMD_SUCCESS;
2412}
2413
2414/* Help display function for all node. */
2415DEFUN (config_help,
2416 config_help_cmd,
2417 "help",
2418 "Description of the interactive help system\n")
2419{
2420 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002421 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002422anytime at the command line please press '?'.%s\
2423%s\
2424If nothing matches, the help list will be empty and you must backup%s\
2425 until entering a '?' shows the available options.%s\
2426Two styles of help are provided:%s\
24271. Full help is available when you are ready to enter a%s\
2428command argument (e.g. 'show ?') and describes each possible%s\
2429argument.%s\
24302. Partial help is provided when an abbreviated argument is entered%s\
2431 and you want to know what arguments match the input%s\
2432 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2433 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2434 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2435 return CMD_SUCCESS;
2436}
2437
2438/* Help display function for all node. */
2439DEFUN (config_list,
2440 config_list_cmd,
2441 "list",
2442 "Print command list\n")
2443{
hasso8c328f12004-10-05 21:01:23 +00002444 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002445 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2446 struct cmd_element *cmd;
2447
2448 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2449 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2450 vty_out (vty, " %s%s", cmd->string,
2451 VTY_NEWLINE);
2452 return CMD_SUCCESS;
2453}
2454
2455/* 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{
hasso8c328f12004-10-05 21:01:23 +00002462 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002463 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 {
2473 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2474 VTY_NEWLINE);
2475 return CMD_WARNING;
2476 }
2477
2478 /* Get filename. */
2479 config_file = host.config;
2480
2481 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2482 strcpy (config_file_sav, config_file);
2483 strcat (config_file_sav, CONF_BACKUP_EXT);
2484
2485
2486 config_file_tmp = malloc (strlen (config_file) + 8);
2487 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2488
2489 /* Open file to configuration write. */
2490 fd = mkstemp (config_file_tmp);
2491 if (fd < 0)
2492 {
2493 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2494 VTY_NEWLINE);
2495 free (config_file_tmp);
2496 free (config_file_sav);
2497 return CMD_WARNING;
2498 }
2499
2500 /* Make vty for configuration file. */
2501 file_vty = vty_new ();
2502 file_vty->fd = fd;
2503 file_vty->type = VTY_FILE;
2504
2505 /* Config file header print. */
2506 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2507 vty_time_print (file_vty, 1);
2508 vty_out (file_vty, "!\n");
2509
2510 for (i = 0; i < vector_max (cmdvec); i++)
2511 if ((node = vector_slot (cmdvec, i)) && node->func)
2512 {
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 {
2521 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2522 VTY_NEWLINE);
2523 free (config_file_sav);
2524 free (config_file_tmp);
2525 unlink (config_file_tmp);
2526 return CMD_WARNING;
2527 }
2528 if (link (config_file, config_file_sav) != 0)
2529 {
2530 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2531 VTY_NEWLINE);
2532 free (config_file_sav);
2533 free (config_file_tmp);
2534 unlink (config_file_tmp);
2535 return CMD_WARNING;
2536 }
2537 sync ();
2538 if (unlink (config_file) != 0)
2539 {
2540 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2541 VTY_NEWLINE);
2542 free (config_file_sav);
2543 free (config_file_tmp);
2544 unlink (config_file_tmp);
2545 return CMD_WARNING;
2546 }
2547 if (link (config_file_tmp, config_file) != 0)
2548 {
2549 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2550 VTY_NEWLINE);
2551 free (config_file_sav);
2552 free (config_file_tmp);
2553 unlink (config_file_tmp);
2554 return CMD_WARNING;
2555 }
2556 unlink (config_file_tmp);
2557 sync ();
2558
2559 free (config_file_sav);
2560 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002561
2562 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2563 {
2564 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
2565 config_file, strerror(errno), errno, VTY_NEWLINE);
2566 return CMD_WARNING;
2567 }
2568
paul718e3742002-12-13 20:15:29 +00002569 vty_out (vty, "Configuration saved to %s%s", config_file,
2570 VTY_NEWLINE);
2571 return CMD_SUCCESS;
2572}
2573
2574ALIAS (config_write_file,
2575 config_write_cmd,
2576 "write",
2577 "Write running configuration to memory, network, or terminal\n")
2578
2579ALIAS (config_write_file,
2580 config_write_memory_cmd,
2581 "write memory",
2582 "Write running configuration to memory, network, or terminal\n"
2583 "Write configuration to the file (same as write file)\n")
2584
2585ALIAS (config_write_file,
2586 copy_runningconfig_startupconfig_cmd,
2587 "copy running-config startup-config",
2588 "Copy configuration\n"
2589 "Copy running config to... \n"
2590 "Copy running config to startup config (same as write file)\n")
2591
2592/* Write current configuration into the terminal. */
2593DEFUN (config_write_terminal,
2594 config_write_terminal_cmd,
2595 "write terminal",
2596 "Write running configuration to memory, network, or terminal\n"
2597 "Write to terminal\n")
2598{
hasso8c328f12004-10-05 21:01:23 +00002599 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002600 struct cmd_node *node;
2601
2602 if (vty->type == VTY_SHELL_SERV)
2603 {
2604 for (i = 0; i < vector_max (cmdvec); i++)
2605 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2606 {
2607 if ((*node->func) (vty))
2608 vty_out (vty, "!%s", VTY_NEWLINE);
2609 }
2610 }
2611 else
2612 {
2613 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2614 VTY_NEWLINE);
2615 vty_out (vty, "!%s", VTY_NEWLINE);
2616
2617 for (i = 0; i < vector_max (cmdvec); i++)
2618 if ((node = vector_slot (cmdvec, i)) && node->func)
2619 {
2620 if ((*node->func) (vty))
2621 vty_out (vty, "!%s", VTY_NEWLINE);
2622 }
2623 vty_out (vty, "end%s",VTY_NEWLINE);
2624 }
2625 return CMD_SUCCESS;
2626}
2627
2628/* Write current configuration into the terminal. */
2629ALIAS (config_write_terminal,
2630 show_running_config_cmd,
2631 "show running-config",
2632 SHOW_STR
2633 "running configuration\n")
2634
2635/* Write startup configuration into the terminal. */
2636DEFUN (show_startup_config,
2637 show_startup_config_cmd,
2638 "show startup-config",
2639 SHOW_STR
2640 "Contentes of startup configuration\n")
2641{
2642 char buf[BUFSIZ];
2643 FILE *confp;
2644
2645 confp = fopen (host.config, "r");
2646 if (confp == NULL)
2647 {
2648 vty_out (vty, "Can't open configuration file [%s]%s",
2649 host.config, VTY_NEWLINE);
2650 return CMD_WARNING;
2651 }
2652
2653 while (fgets (buf, BUFSIZ, confp))
2654 {
2655 char *cp = buf;
2656
2657 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2658 cp++;
2659 *cp = '\0';
2660
2661 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2662 }
2663
2664 fclose (confp);
2665
2666 return CMD_SUCCESS;
2667}
2668
2669/* Hostname configuration */
2670DEFUN (config_hostname,
2671 hostname_cmd,
2672 "hostname WORD",
2673 "Set system's network name\n"
2674 "This system's network name\n")
2675{
2676 if (!isalpha((int) *argv[0]))
2677 {
2678 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2679 return CMD_WARNING;
2680 }
2681
2682 if (host.name)
2683 XFREE (0, host.name);
2684
2685 host.name = strdup (argv[0]);
2686 return CMD_SUCCESS;
2687}
2688
2689DEFUN (config_no_hostname,
2690 no_hostname_cmd,
2691 "no hostname [HOSTNAME]",
2692 NO_STR
2693 "Reset system's network name\n"
2694 "Host name of this router\n")
2695{
2696 if (host.name)
2697 XFREE (0, host.name);
2698 host.name = NULL;
2699 return CMD_SUCCESS;
2700}
2701
2702/* VTY interface password set. */
2703DEFUN (config_password, password_cmd,
2704 "password (8|) WORD",
2705 "Assign the terminal connection password\n"
2706 "Specifies a HIDDEN password will follow\n"
2707 "dummy string \n"
2708 "The HIDDEN line password string\n")
2709{
2710 /* Argument check. */
2711 if (argc == 0)
2712 {
2713 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2714 return CMD_WARNING;
2715 }
2716
2717 if (argc == 2)
2718 {
2719 if (*argv[0] == '8')
2720 {
2721 if (host.password)
2722 XFREE (0, host.password);
2723 host.password = NULL;
2724 if (host.password_encrypt)
2725 XFREE (0, host.password_encrypt);
2726 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2727 return CMD_SUCCESS;
2728 }
2729 else
2730 {
2731 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2732 return CMD_WARNING;
2733 }
2734 }
2735
2736 if (!isalnum ((int) *argv[0]))
2737 {
2738 vty_out (vty,
2739 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2740 return CMD_WARNING;
2741 }
2742
2743 if (host.password)
2744 XFREE (0, host.password);
2745 host.password = NULL;
2746
2747 if (host.encrypt)
2748 {
2749 if (host.password_encrypt)
2750 XFREE (0, host.password_encrypt);
2751 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2752 }
2753 else
2754 host.password = XSTRDUP (0, argv[0]);
2755
2756 return CMD_SUCCESS;
2757}
2758
2759ALIAS (config_password, password_text_cmd,
2760 "password LINE",
2761 "Assign the terminal connection password\n"
2762 "The UNENCRYPTED (cleartext) line password\n")
2763
2764/* VTY enable password set. */
2765DEFUN (config_enable_password, enable_password_cmd,
2766 "enable password (8|) WORD",
2767 "Modify enable password parameters\n"
2768 "Assign the privileged level password\n"
2769 "Specifies a HIDDEN password will follow\n"
2770 "dummy string \n"
2771 "The HIDDEN 'enable' password string\n")
2772{
2773 /* Argument check. */
2774 if (argc == 0)
2775 {
2776 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2777 return CMD_WARNING;
2778 }
2779
2780 /* Crypt type is specified. */
2781 if (argc == 2)
2782 {
2783 if (*argv[0] == '8')
2784 {
2785 if (host.enable)
2786 XFREE (0, host.enable);
2787 host.enable = NULL;
2788
2789 if (host.enable_encrypt)
2790 XFREE (0, host.enable_encrypt);
2791 host.enable_encrypt = XSTRDUP (0, argv[1]);
2792
2793 return CMD_SUCCESS;
2794 }
2795 else
2796 {
2797 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2798 return CMD_WARNING;
2799 }
2800 }
2801
2802 if (!isalnum ((int) *argv[0]))
2803 {
2804 vty_out (vty,
2805 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2806 return CMD_WARNING;
2807 }
2808
2809 if (host.enable)
2810 XFREE (0, host.enable);
2811 host.enable = NULL;
2812
2813 /* Plain password input. */
2814 if (host.encrypt)
2815 {
2816 if (host.enable_encrypt)
2817 XFREE (0, host.enable_encrypt);
2818 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2819 }
2820 else
2821 host.enable = XSTRDUP (0, argv[0]);
2822
2823 return CMD_SUCCESS;
2824}
2825
2826ALIAS (config_enable_password,
2827 enable_password_text_cmd,
2828 "enable password LINE",
2829 "Modify enable password parameters\n"
2830 "Assign the privileged level password\n"
2831 "The UNENCRYPTED (cleartext) 'enable' password\n")
2832
2833/* VTY enable password delete. */
2834DEFUN (no_config_enable_password, no_enable_password_cmd,
2835 "no enable password",
2836 NO_STR
2837 "Modify enable password parameters\n"
2838 "Assign the privileged level password\n")
2839{
2840 if (host.enable)
2841 XFREE (0, host.enable);
2842 host.enable = NULL;
2843
2844 if (host.enable_encrypt)
2845 XFREE (0, host.enable_encrypt);
2846 host.enable_encrypt = NULL;
2847
2848 return CMD_SUCCESS;
2849}
2850
2851DEFUN (service_password_encrypt,
2852 service_password_encrypt_cmd,
2853 "service password-encryption",
2854 "Set up miscellaneous service\n"
2855 "Enable encrypted passwords\n")
2856{
2857 if (host.encrypt)
2858 return CMD_SUCCESS;
2859
2860 host.encrypt = 1;
2861
2862 if (host.password)
2863 {
2864 if (host.password_encrypt)
2865 XFREE (0, host.password_encrypt);
2866 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2867 }
2868 if (host.enable)
2869 {
2870 if (host.enable_encrypt)
2871 XFREE (0, host.enable_encrypt);
2872 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2873 }
2874
2875 return CMD_SUCCESS;
2876}
2877
2878DEFUN (no_service_password_encrypt,
2879 no_service_password_encrypt_cmd,
2880 "no service password-encryption",
2881 NO_STR
2882 "Set up miscellaneous service\n"
2883 "Enable encrypted passwords\n")
2884{
2885 if (! host.encrypt)
2886 return CMD_SUCCESS;
2887
2888 host.encrypt = 0;
2889
2890 if (host.password_encrypt)
2891 XFREE (0, host.password_encrypt);
2892 host.password_encrypt = NULL;
2893
2894 if (host.enable_encrypt)
2895 XFREE (0, host.enable_encrypt);
2896 host.enable_encrypt = NULL;
2897
2898 return CMD_SUCCESS;
2899}
2900
2901DEFUN (config_terminal_length, config_terminal_length_cmd,
2902 "terminal length <0-512>",
2903 "Set terminal line parameters\n"
2904 "Set number of lines on a screen\n"
2905 "Number of lines on screen (0 for no pausing)\n")
2906{
2907 int lines;
2908 char *endptr = NULL;
2909
2910 lines = strtol (argv[0], &endptr, 10);
2911 if (lines < 0 || lines > 512 || *endptr != '\0')
2912 {
2913 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2914 return CMD_WARNING;
2915 }
2916 vty->lines = lines;
2917
2918 return CMD_SUCCESS;
2919}
2920
2921DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2922 "terminal no length",
2923 "Set terminal line parameters\n"
2924 NO_STR
2925 "Set number of lines on a screen\n")
2926{
2927 vty->lines = -1;
2928 return CMD_SUCCESS;
2929}
2930
2931DEFUN (service_terminal_length, service_terminal_length_cmd,
2932 "service terminal-length <0-512>",
2933 "Set up miscellaneous service\n"
2934 "System wide terminal length configuration\n"
2935 "Number of lines of VTY (0 means no line control)\n")
2936{
2937 int lines;
2938 char *endptr = NULL;
2939
2940 lines = strtol (argv[0], &endptr, 10);
2941 if (lines < 0 || lines > 512 || *endptr != '\0')
2942 {
2943 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2944 return CMD_WARNING;
2945 }
2946 host.lines = lines;
2947
2948 return CMD_SUCCESS;
2949}
2950
2951DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2952 "no service terminal-length [<0-512>]",
2953 NO_STR
2954 "Set up miscellaneous service\n"
2955 "System wide terminal length configuration\n"
2956 "Number of lines of VTY (0 means no line control)\n")
2957{
2958 host.lines = -1;
2959 return CMD_SUCCESS;
2960}
2961
2962DEFUN (config_log_stdout,
2963 config_log_stdout_cmd,
2964 "log stdout",
2965 "Logging control\n"
2966 "Logging goes to stdout\n")
2967{
2968 zlog_set_flag (NULL, ZLOG_STDOUT);
2969 host.log_stdout = 1;
2970 return CMD_SUCCESS;
2971}
2972
2973DEFUN (no_config_log_stdout,
2974 no_config_log_stdout_cmd,
2975 "no log stdout",
2976 NO_STR
2977 "Logging control\n"
2978 "Cancel logging to stdout\n")
2979{
2980 zlog_reset_flag (NULL, ZLOG_STDOUT);
2981 host.log_stdout = 0;
2982 return CMD_SUCCESS;
2983}
2984
2985DEFUN (config_log_file,
2986 config_log_file_cmd,
2987 "log file FILENAME",
2988 "Logging control\n"
2989 "Logging to file\n"
2990 "Logging filename\n")
2991{
2992 int ret;
paul9035efa2004-10-10 11:56:56 +00002993 char *p = NULL;
2994 const char *fullpath;
2995
paul718e3742002-12-13 20:15:29 +00002996 /* Path detection. */
2997 if (! IS_DIRECTORY_SEP (*argv[0]))
2998 {
paul9035efa2004-10-10 11:56:56 +00002999 char cwd[MAXPATHLEN+1];
3000 cwd[MAXPATHLEN] = '\0';
3001
3002 if (getcwd (cwd, MAXPATHLEN) == NULL)
3003 {
3004 zlog_err ("config_log_file: Unable to alloc mem!");
3005 return CMD_WARNING;
3006 }
3007
3008 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (argv[0]) + 2))
3009 == NULL)
3010 {
3011 zlog_err ("config_log_file: Unable to alloc mem!");
3012 return CMD_WARNING;
3013 }
3014 sprintf (p, "%s/%s", cwd, argv[0]);
3015 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003016 }
3017 else
3018 fullpath = argv[0];
3019
3020 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
3021
paul9035efa2004-10-10 11:56:56 +00003022 if (p)
3023 XFREE (MTYPE_TMP, p);
3024
paul718e3742002-12-13 20:15:29 +00003025 if (!ret)
3026 {
3027 vty_out (vty, "can't open logfile %s\n", argv[0]);
3028 return CMD_WARNING;
3029 }
3030
3031 if (host.logfile)
3032 XFREE (MTYPE_TMP, host.logfile);
3033
3034 host.logfile = strdup (argv[0]);
3035
3036 return CMD_SUCCESS;
3037}
3038
3039DEFUN (no_config_log_file,
3040 no_config_log_file_cmd,
3041 "no log file [FILENAME]",
3042 NO_STR
3043 "Logging control\n"
3044 "Cancel logging to file\n"
3045 "Logging file name\n")
3046{
3047 zlog_reset_file (NULL);
3048
3049 if (host.logfile)
3050 XFREE (MTYPE_TMP, host.logfile);
3051
3052 host.logfile = NULL;
3053
3054 return CMD_SUCCESS;
3055}
3056
3057DEFUN (config_log_syslog,
3058 config_log_syslog_cmd,
3059 "log syslog",
3060 "Logging control\n"
3061 "Logging goes to syslog\n")
3062{
3063 zlog_set_flag (NULL, ZLOG_SYSLOG);
3064 host.log_syslog = 1;
paul12ab19f2003-07-26 06:14:55 +00003065 zlog_default->facility = LOG_DAEMON;
3066 return CMD_SUCCESS;
3067}
3068
3069DEFUN (config_log_syslog_facility,
3070 config_log_syslog_facility_cmd,
3071 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3072 "Logging control\n"
3073 "Logging goes to syslog\n"
3074 "Facility parameter for syslog messages\n"
3075 "Kernel\n"
3076 "User process\n"
3077 "Mail system\n"
3078 "System daemons\n"
3079 "Authorization system\n"
3080 "Syslog itself\n"
3081 "Line printer system\n"
3082 "USENET news\n"
3083 "Unix-to-Unix copy system\n"
3084 "Cron/at facility\n"
3085 "Local use\n"
3086 "Local use\n"
3087 "Local use\n"
3088 "Local use\n"
3089 "Local use\n"
3090 "Local use\n"
3091 "Local use\n"
3092 "Local use\n")
3093{
3094 int facility = LOG_DAEMON;
3095
3096 zlog_set_flag (NULL, ZLOG_SYSLOG);
3097 host.log_syslog = 1;
3098
3099 if (strncmp (argv[0], "kern", 1) == 0)
3100 facility = LOG_KERN;
3101 else if (strncmp (argv[0], "user", 2) == 0)
3102 facility = LOG_USER;
3103 else if (strncmp (argv[0], "mail", 1) == 0)
3104 facility = LOG_MAIL;
3105 else if (strncmp (argv[0], "daemon", 1) == 0)
3106 facility = LOG_DAEMON;
3107 else if (strncmp (argv[0], "auth", 1) == 0)
3108 facility = LOG_AUTH;
3109 else if (strncmp (argv[0], "syslog", 1) == 0)
3110 facility = LOG_SYSLOG;
3111 else if (strncmp (argv[0], "lpr", 2) == 0)
3112 facility = LOG_LPR;
3113 else if (strncmp (argv[0], "news", 1) == 0)
3114 facility = LOG_NEWS;
3115 else if (strncmp (argv[0], "uucp", 2) == 0)
3116 facility = LOG_UUCP;
3117 else if (strncmp (argv[0], "cron", 1) == 0)
3118 facility = LOG_CRON;
3119 else if (strncmp (argv[0], "local0", 6) == 0)
3120 facility = LOG_LOCAL0;
3121 else if (strncmp (argv[0], "local1", 6) == 0)
3122 facility = LOG_LOCAL1;
3123 else if (strncmp (argv[0], "local2", 6) == 0)
3124 facility = LOG_LOCAL2;
3125 else if (strncmp (argv[0], "local3", 6) == 0)
3126 facility = LOG_LOCAL3;
3127 else if (strncmp (argv[0], "local4", 6) == 0)
3128 facility = LOG_LOCAL4;
3129 else if (strncmp (argv[0], "local5", 6) == 0)
3130 facility = LOG_LOCAL5;
3131 else if (strncmp (argv[0], "local6", 6) == 0)
3132 facility = LOG_LOCAL6;
3133 else if (strncmp (argv[0], "local7", 6) == 0)
3134 facility = LOG_LOCAL7;
3135
3136 zlog_default->facility = facility;
3137
paul718e3742002-12-13 20:15:29 +00003138 return CMD_SUCCESS;
3139}
3140
3141DEFUN (no_config_log_syslog,
3142 no_config_log_syslog_cmd,
3143 "no log syslog",
3144 NO_STR
3145 "Logging control\n"
3146 "Cancel logging to syslog\n")
3147{
3148 zlog_reset_flag (NULL, ZLOG_SYSLOG);
3149 host.log_syslog = 0;
paul12ab19f2003-07-26 06:14:55 +00003150 zlog_default->facility = LOG_DAEMON;
paul718e3742002-12-13 20:15:29 +00003151 return CMD_SUCCESS;
3152}
3153
paul12ab19f2003-07-26 06:14:55 +00003154ALIAS (no_config_log_syslog,
3155 no_config_log_syslog_facility_cmd,
3156 "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3157 NO_STR
3158 "Logging control\n"
3159 "Logging goes to syslog\n"
3160 "Facility parameter for syslog messages\n"
3161 "Kernel\n"
3162 "User process\n"
3163 "Mail system\n"
3164 "System daemons\n"
3165 "Authorization system\n"
3166 "Syslog itself\n"
3167 "Line printer system\n"
3168 "USENET news\n"
3169 "Unix-to-Unix copy system\n"
3170 "Cron/at facility\n"
3171 "Local use\n"
3172 "Local use\n"
3173 "Local use\n"
3174 "Local use\n"
3175 "Local use\n"
3176 "Local use\n"
3177 "Local use\n"
3178 "Local use\n")
3179
paul718e3742002-12-13 20:15:29 +00003180DEFUN (config_log_trap,
3181 config_log_trap_cmd,
3182 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3183 "Logging control\n"
3184 "Limit logging to specifed level\n")
3185{
3186 int new_level ;
3187
3188 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
3189 {
3190 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
3191 /* found new logging level */
3192 {
3193 zlog_default->maskpri = new_level;
3194 return CMD_SUCCESS;
3195 }
3196 }
3197 return CMD_ERR_NO_MATCH;
3198}
3199
3200DEFUN (no_config_log_trap,
3201 no_config_log_trap_cmd,
3202 "no log trap",
3203 NO_STR
3204 "Logging control\n"
3205 "Permit all logging information\n")
3206{
3207 zlog_default->maskpri = LOG_DEBUG;
3208 return CMD_SUCCESS;
3209}
3210
3211DEFUN (config_log_record_priority,
3212 config_log_record_priority_cmd,
3213 "log record-priority",
3214 "Logging control\n"
3215 "Log the priority of the message within the message\n")
3216{
3217 zlog_default->record_priority = 1 ;
3218 return CMD_SUCCESS;
3219}
3220
3221DEFUN (no_config_log_record_priority,
3222 no_config_log_record_priority_cmd,
3223 "no log record-priority",
3224 NO_STR
3225 "Logging control\n"
3226 "Do not log the priority of the message within the message\n")
3227{
3228 zlog_default->record_priority = 0 ;
3229 return CMD_SUCCESS;
3230}
3231
3232
3233DEFUN (banner_motd_default,
3234 banner_motd_default_cmd,
3235 "banner motd default",
3236 "Set banner string\n"
3237 "Strings for motd\n"
3238 "Default string\n")
3239{
3240 host.motd = default_motd;
3241 return CMD_SUCCESS;
3242}
3243
3244DEFUN (no_banner_motd,
3245 no_banner_motd_cmd,
3246 "no banner motd",
3247 NO_STR
3248 "Set banner string\n"
3249 "Strings for motd\n")
3250{
3251 host.motd = NULL;
3252 return CMD_SUCCESS;
3253}
3254
3255/* Set config filename. Called from vty.c */
3256void
3257host_config_set (char *filename)
3258{
3259 host.config = strdup (filename);
3260}
3261
3262void
3263install_default (enum node_type node)
3264{
3265 install_element (node, &config_exit_cmd);
3266 install_element (node, &config_quit_cmd);
3267 install_element (node, &config_end_cmd);
3268 install_element (node, &config_help_cmd);
3269 install_element (node, &config_list_cmd);
3270
3271 install_element (node, &config_write_terminal_cmd);
3272 install_element (node, &config_write_file_cmd);
3273 install_element (node, &config_write_memory_cmd);
3274 install_element (node, &config_write_cmd);
3275 install_element (node, &show_running_config_cmd);
3276}
3277
3278/* Initialize command interface. Install basic nodes and commands. */
3279void
3280cmd_init (int terminal)
3281{
3282 /* Allocate initial top vector of commands. */
3283 cmdvec = vector_init (VECTOR_MIN_SIZE);
3284
3285 /* Default host value settings. */
3286 host.name = NULL;
3287 host.password = NULL;
3288 host.enable = NULL;
3289 host.logfile = NULL;
3290 host.config = NULL;
3291 host.lines = -1;
3292 host.motd = default_motd;
3293
3294 /* Install top nodes. */
3295 install_node (&view_node, NULL);
3296 install_node (&enable_node, NULL);
3297 install_node (&auth_node, NULL);
3298 install_node (&auth_enable_node, NULL);
3299 install_node (&config_node, config_write_host);
3300
3301 /* Each node's basic commands. */
3302 install_element (VIEW_NODE, &show_version_cmd);
3303 if (terminal)
3304 {
3305 install_element (VIEW_NODE, &config_list_cmd);
3306 install_element (VIEW_NODE, &config_exit_cmd);
3307 install_element (VIEW_NODE, &config_quit_cmd);
3308 install_element (VIEW_NODE, &config_help_cmd);
3309 install_element (VIEW_NODE, &config_enable_cmd);
3310 install_element (VIEW_NODE, &config_terminal_length_cmd);
3311 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3312 }
3313
3314 if (terminal)
3315 {
3316 install_default (ENABLE_NODE);
3317 install_element (ENABLE_NODE, &config_disable_cmd);
3318 install_element (ENABLE_NODE, &config_terminal_cmd);
3319 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3320 }
3321 install_element (ENABLE_NODE, &show_startup_config_cmd);
3322 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003323
3324 if (terminal)
paul718e3742002-12-13 20:15:29 +00003325 {
hassoe7168df2004-10-03 20:11:32 +00003326 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3327 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3328
3329 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003330 }
3331
3332 install_element (CONFIG_NODE, &hostname_cmd);
3333 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003334
hassoea8e9d92004-10-07 21:32:14 +00003335 if (terminal)
3336 {
hassoe7168df2004-10-03 20:11:32 +00003337 install_element (CONFIG_NODE, &password_cmd);
3338 install_element (CONFIG_NODE, &password_text_cmd);
3339 install_element (CONFIG_NODE, &enable_password_cmd);
3340 install_element (CONFIG_NODE, &enable_password_text_cmd);
3341 install_element (CONFIG_NODE, &no_enable_password_cmd);
3342
paul718e3742002-12-13 20:15:29 +00003343 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3344 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3345 install_element (CONFIG_NODE, &config_log_file_cmd);
3346 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3347 install_element (CONFIG_NODE, &config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003348 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003349 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003350 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003351 install_element (CONFIG_NODE, &config_log_trap_cmd);
3352 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3353 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3354 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3355 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3356 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3357 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3358 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3359 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3360 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003361
paul9ab68122003-01-18 01:16:20 +00003362 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3363 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3364 }
paul718e3742002-12-13 20:15:29 +00003365 srand(time(NULL));
3366}