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