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