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