blob: 4495d2213c68e186d507a78347c12cfe988ccf00 [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
hassoddd85ed2004-10-13 08:18:07 +00002241 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2242 {
paulb92938a2002-12-13 21:20:42 +00002243 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002244 ret = cmd_execute_command_strict (vline, vty, NULL);
2245 }
paul9ab68122003-01-18 01:16:20 +00002246
paul718e3742002-12-13 20:15:29 +00002247 cmd_free_strvec (vline);
2248
hassoddd85ed2004-10-13 08:18:07 +00002249 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2250 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002251 return ret;
2252 }
2253 return CMD_SUCCESS;
2254}
2255
2256/* Configration from terminal */
2257DEFUN (config_terminal,
2258 config_terminal_cmd,
2259 "configure terminal",
2260 "Configuration from vty interface\n"
2261 "Configuration terminal\n")
2262{
2263 if (vty_config_lock (vty))
2264 vty->node = CONFIG_NODE;
2265 else
2266 {
2267 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2268 return CMD_WARNING;
2269 }
2270 return CMD_SUCCESS;
2271}
2272
2273/* Enable command */
2274DEFUN (enable,
2275 config_enable_cmd,
2276 "enable",
2277 "Turn on privileged mode command\n")
2278{
2279 /* If enable password is NULL, change to ENABLE_NODE */
2280 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2281 vty->type == VTY_SHELL_SERV)
2282 vty->node = ENABLE_NODE;
2283 else
2284 vty->node = AUTH_ENABLE_NODE;
2285
2286 return CMD_SUCCESS;
2287}
2288
2289/* Disable command */
2290DEFUN (disable,
2291 config_disable_cmd,
2292 "disable",
2293 "Turn off privileged mode command\n")
2294{
2295 if (vty->node == ENABLE_NODE)
2296 vty->node = VIEW_NODE;
2297 return CMD_SUCCESS;
2298}
2299
2300/* Down vty node level. */
2301DEFUN (config_exit,
2302 config_exit_cmd,
2303 "exit",
2304 "Exit current mode and down to previous mode\n")
2305{
2306 switch (vty->node)
2307 {
2308 case VIEW_NODE:
2309 case ENABLE_NODE:
2310 if (vty_shell (vty))
2311 exit (0);
2312 else
2313 vty->status = VTY_CLOSE;
2314 break;
2315 case CONFIG_NODE:
2316 vty->node = ENABLE_NODE;
2317 vty_config_unlock (vty);
2318 break;
2319 case INTERFACE_NODE:
2320 case ZEBRA_NODE:
2321 case BGP_NODE:
2322 case RIP_NODE:
2323 case RIPNG_NODE:
2324 case OSPF_NODE:
2325 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002326 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002327 case KEYCHAIN_NODE:
2328 case MASC_NODE:
2329 case RMAP_NODE:
2330 case VTY_NODE:
2331 vty->node = CONFIG_NODE;
2332 break;
2333 case BGP_VPNV4_NODE:
2334 case BGP_IPV4_NODE:
2335 case BGP_IPV4M_NODE:
2336 case BGP_IPV6_NODE:
2337 vty->node = BGP_NODE;
2338 break;
2339 case KEYCHAIN_KEY_NODE:
2340 vty->node = KEYCHAIN_NODE;
2341 break;
2342 default:
2343 break;
2344 }
2345 return CMD_SUCCESS;
2346}
2347
2348/* quit is alias of exit. */
2349ALIAS (config_exit,
2350 config_quit_cmd,
2351 "quit",
2352 "Exit current mode and down to previous mode\n")
2353
2354/* End of configuration. */
2355DEFUN (config_end,
2356 config_end_cmd,
2357 "end",
2358 "End current mode and change to enable mode.")
2359{
2360 switch (vty->node)
2361 {
2362 case VIEW_NODE:
2363 case ENABLE_NODE:
2364 /* Nothing to do. */
2365 break;
2366 case CONFIG_NODE:
2367 case INTERFACE_NODE:
2368 case ZEBRA_NODE:
2369 case RIP_NODE:
2370 case RIPNG_NODE:
2371 case BGP_NODE:
2372 case BGP_VPNV4_NODE:
2373 case BGP_IPV4_NODE:
2374 case BGP_IPV4M_NODE:
2375 case BGP_IPV6_NODE:
2376 case RMAP_NODE:
2377 case OSPF_NODE:
2378 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002379 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002380 case KEYCHAIN_NODE:
2381 case KEYCHAIN_KEY_NODE:
2382 case MASC_NODE:
2383 case VTY_NODE:
2384 vty_config_unlock (vty);
2385 vty->node = ENABLE_NODE;
2386 break;
2387 default:
2388 break;
2389 }
2390 return CMD_SUCCESS;
2391}
2392
2393/* Show version. */
2394DEFUN (show_version,
2395 show_version_cmd,
2396 "show version",
2397 SHOW_STR
2398 "Displays zebra version\n")
2399{
paule8f29842003-08-12 13:08:31 +00002400 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION,
paul718e3742002-12-13 20:15:29 +00002401 host_name,
2402 VTY_NEWLINE);
2403 vty_out (vty, "Copyright 1996-2002, Kunihiro Ishiguro.%s", VTY_NEWLINE);
2404
2405 return CMD_SUCCESS;
2406}
2407
2408/* Help display function for all node. */
2409DEFUN (config_help,
2410 config_help_cmd,
2411 "help",
2412 "Description of the interactive help system\n")
2413{
2414 vty_out (vty,
2415 "Zebra VTY provides advanced help feature. When you need help,%s\
2416anytime at the command line please press '?'.%s\
2417%s\
2418If nothing matches, the help list will be empty and you must backup%s\
2419 until entering a '?' shows the available options.%s\
2420Two styles of help are provided:%s\
24211. Full help is available when you are ready to enter a%s\
2422command argument (e.g. 'show ?') and describes each possible%s\
2423argument.%s\
24242. Partial help is provided when an abbreviated argument is entered%s\
2425 and you want to know what arguments match the input%s\
2426 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2427 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2428 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2429 return CMD_SUCCESS;
2430}
2431
2432/* Help display function for all node. */
2433DEFUN (config_list,
2434 config_list_cmd,
2435 "list",
2436 "Print command list\n")
2437{
hasso8c328f12004-10-05 21:01:23 +00002438 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002439 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2440 struct cmd_element *cmd;
2441
2442 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2443 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2444 vty_out (vty, " %s%s", cmd->string,
2445 VTY_NEWLINE);
2446 return CMD_SUCCESS;
2447}
2448
2449/* Write current configuration into file. */
2450DEFUN (config_write_file,
2451 config_write_file_cmd,
2452 "write file",
2453 "Write running configuration to memory, network, or terminal\n"
2454 "Write to configuration file\n")
2455{
hasso8c328f12004-10-05 21:01:23 +00002456 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002457 int fd;
2458 struct cmd_node *node;
2459 char *config_file;
2460 char *config_file_tmp = NULL;
2461 char *config_file_sav = NULL;
2462 struct vty *file_vty;
2463
2464 /* Check and see if we are operating under vtysh configuration */
2465 if (host.config == NULL)
2466 {
2467 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2468 VTY_NEWLINE);
2469 return CMD_WARNING;
2470 }
2471
2472 /* Get filename. */
2473 config_file = host.config;
2474
2475 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2476 strcpy (config_file_sav, config_file);
2477 strcat (config_file_sav, CONF_BACKUP_EXT);
2478
2479
2480 config_file_tmp = malloc (strlen (config_file) + 8);
2481 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2482
2483 /* Open file to configuration write. */
2484 fd = mkstemp (config_file_tmp);
2485 if (fd < 0)
2486 {
2487 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2488 VTY_NEWLINE);
2489 free (config_file_tmp);
2490 free (config_file_sav);
2491 return CMD_WARNING;
2492 }
2493
2494 /* Make vty for configuration file. */
2495 file_vty = vty_new ();
2496 file_vty->fd = fd;
2497 file_vty->type = VTY_FILE;
2498
2499 /* Config file header print. */
2500 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2501 vty_time_print (file_vty, 1);
2502 vty_out (file_vty, "!\n");
2503
2504 for (i = 0; i < vector_max (cmdvec); i++)
2505 if ((node = vector_slot (cmdvec, i)) && node->func)
2506 {
2507 if ((*node->func) (file_vty))
2508 vty_out (file_vty, "!\n");
2509 }
2510 vty_close (file_vty);
2511
2512 if (unlink (config_file_sav) != 0)
2513 if (errno != ENOENT)
2514 {
2515 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2516 VTY_NEWLINE);
2517 free (config_file_sav);
2518 free (config_file_tmp);
2519 unlink (config_file_tmp);
2520 return CMD_WARNING;
2521 }
2522 if (link (config_file, config_file_sav) != 0)
2523 {
2524 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2525 VTY_NEWLINE);
2526 free (config_file_sav);
2527 free (config_file_tmp);
2528 unlink (config_file_tmp);
2529 return CMD_WARNING;
2530 }
2531 sync ();
2532 if (unlink (config_file) != 0)
2533 {
2534 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2535 VTY_NEWLINE);
2536 free (config_file_sav);
2537 free (config_file_tmp);
2538 unlink (config_file_tmp);
2539 return CMD_WARNING;
2540 }
2541 if (link (config_file_tmp, config_file) != 0)
2542 {
2543 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2544 VTY_NEWLINE);
2545 free (config_file_sav);
2546 free (config_file_tmp);
2547 unlink (config_file_tmp);
2548 return CMD_WARNING;
2549 }
2550 unlink (config_file_tmp);
2551 sync ();
2552
2553 free (config_file_sav);
2554 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002555
2556 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2557 {
2558 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
2559 config_file, strerror(errno), errno, VTY_NEWLINE);
2560 return CMD_WARNING;
2561 }
2562
paul718e3742002-12-13 20:15:29 +00002563 vty_out (vty, "Configuration saved to %s%s", config_file,
2564 VTY_NEWLINE);
2565 return CMD_SUCCESS;
2566}
2567
2568ALIAS (config_write_file,
2569 config_write_cmd,
2570 "write",
2571 "Write running configuration to memory, network, or terminal\n")
2572
2573ALIAS (config_write_file,
2574 config_write_memory_cmd,
2575 "write memory",
2576 "Write running configuration to memory, network, or terminal\n"
2577 "Write configuration to the file (same as write file)\n")
2578
2579ALIAS (config_write_file,
2580 copy_runningconfig_startupconfig_cmd,
2581 "copy running-config startup-config",
2582 "Copy configuration\n"
2583 "Copy running config to... \n"
2584 "Copy running config to startup config (same as write file)\n")
2585
2586/* Write current configuration into the terminal. */
2587DEFUN (config_write_terminal,
2588 config_write_terminal_cmd,
2589 "write terminal",
2590 "Write running configuration to memory, network, or terminal\n"
2591 "Write to terminal\n")
2592{
hasso8c328f12004-10-05 21:01:23 +00002593 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002594 struct cmd_node *node;
2595
2596 if (vty->type == VTY_SHELL_SERV)
2597 {
2598 for (i = 0; i < vector_max (cmdvec); i++)
2599 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2600 {
2601 if ((*node->func) (vty))
2602 vty_out (vty, "!%s", VTY_NEWLINE);
2603 }
2604 }
2605 else
2606 {
2607 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2608 VTY_NEWLINE);
2609 vty_out (vty, "!%s", VTY_NEWLINE);
2610
2611 for (i = 0; i < vector_max (cmdvec); i++)
2612 if ((node = vector_slot (cmdvec, i)) && node->func)
2613 {
2614 if ((*node->func) (vty))
2615 vty_out (vty, "!%s", VTY_NEWLINE);
2616 }
2617 vty_out (vty, "end%s",VTY_NEWLINE);
2618 }
2619 return CMD_SUCCESS;
2620}
2621
2622/* Write current configuration into the terminal. */
2623ALIAS (config_write_terminal,
2624 show_running_config_cmd,
2625 "show running-config",
2626 SHOW_STR
2627 "running configuration\n")
2628
2629/* Write startup configuration into the terminal. */
2630DEFUN (show_startup_config,
2631 show_startup_config_cmd,
2632 "show startup-config",
2633 SHOW_STR
2634 "Contentes of startup configuration\n")
2635{
2636 char buf[BUFSIZ];
2637 FILE *confp;
2638
2639 confp = fopen (host.config, "r");
2640 if (confp == NULL)
2641 {
2642 vty_out (vty, "Can't open configuration file [%s]%s",
2643 host.config, VTY_NEWLINE);
2644 return CMD_WARNING;
2645 }
2646
2647 while (fgets (buf, BUFSIZ, confp))
2648 {
2649 char *cp = buf;
2650
2651 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2652 cp++;
2653 *cp = '\0';
2654
2655 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2656 }
2657
2658 fclose (confp);
2659
2660 return CMD_SUCCESS;
2661}
2662
2663/* Hostname configuration */
2664DEFUN (config_hostname,
2665 hostname_cmd,
2666 "hostname WORD",
2667 "Set system's network name\n"
2668 "This system's network name\n")
2669{
2670 if (!isalpha((int) *argv[0]))
2671 {
2672 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2673 return CMD_WARNING;
2674 }
2675
2676 if (host.name)
2677 XFREE (0, host.name);
2678
2679 host.name = strdup (argv[0]);
2680 return CMD_SUCCESS;
2681}
2682
2683DEFUN (config_no_hostname,
2684 no_hostname_cmd,
2685 "no hostname [HOSTNAME]",
2686 NO_STR
2687 "Reset system's network name\n"
2688 "Host name of this router\n")
2689{
2690 if (host.name)
2691 XFREE (0, host.name);
2692 host.name = NULL;
2693 return CMD_SUCCESS;
2694}
2695
2696/* VTY interface password set. */
2697DEFUN (config_password, password_cmd,
2698 "password (8|) WORD",
2699 "Assign the terminal connection password\n"
2700 "Specifies a HIDDEN password will follow\n"
2701 "dummy string \n"
2702 "The HIDDEN line password string\n")
2703{
2704 /* Argument check. */
2705 if (argc == 0)
2706 {
2707 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2708 return CMD_WARNING;
2709 }
2710
2711 if (argc == 2)
2712 {
2713 if (*argv[0] == '8')
2714 {
2715 if (host.password)
2716 XFREE (0, host.password);
2717 host.password = NULL;
2718 if (host.password_encrypt)
2719 XFREE (0, host.password_encrypt);
2720 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2721 return CMD_SUCCESS;
2722 }
2723 else
2724 {
2725 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2726 return CMD_WARNING;
2727 }
2728 }
2729
2730 if (!isalnum ((int) *argv[0]))
2731 {
2732 vty_out (vty,
2733 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2734 return CMD_WARNING;
2735 }
2736
2737 if (host.password)
2738 XFREE (0, host.password);
2739 host.password = NULL;
2740
2741 if (host.encrypt)
2742 {
2743 if (host.password_encrypt)
2744 XFREE (0, host.password_encrypt);
2745 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2746 }
2747 else
2748 host.password = XSTRDUP (0, argv[0]);
2749
2750 return CMD_SUCCESS;
2751}
2752
2753ALIAS (config_password, password_text_cmd,
2754 "password LINE",
2755 "Assign the terminal connection password\n"
2756 "The UNENCRYPTED (cleartext) line password\n")
2757
2758/* VTY enable password set. */
2759DEFUN (config_enable_password, enable_password_cmd,
2760 "enable password (8|) WORD",
2761 "Modify enable password parameters\n"
2762 "Assign the privileged level password\n"
2763 "Specifies a HIDDEN password will follow\n"
2764 "dummy string \n"
2765 "The HIDDEN 'enable' password string\n")
2766{
2767 /* Argument check. */
2768 if (argc == 0)
2769 {
2770 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2771 return CMD_WARNING;
2772 }
2773
2774 /* Crypt type is specified. */
2775 if (argc == 2)
2776 {
2777 if (*argv[0] == '8')
2778 {
2779 if (host.enable)
2780 XFREE (0, host.enable);
2781 host.enable = NULL;
2782
2783 if (host.enable_encrypt)
2784 XFREE (0, host.enable_encrypt);
2785 host.enable_encrypt = XSTRDUP (0, argv[1]);
2786
2787 return CMD_SUCCESS;
2788 }
2789 else
2790 {
2791 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2792 return CMD_WARNING;
2793 }
2794 }
2795
2796 if (!isalnum ((int) *argv[0]))
2797 {
2798 vty_out (vty,
2799 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2800 return CMD_WARNING;
2801 }
2802
2803 if (host.enable)
2804 XFREE (0, host.enable);
2805 host.enable = NULL;
2806
2807 /* Plain password input. */
2808 if (host.encrypt)
2809 {
2810 if (host.enable_encrypt)
2811 XFREE (0, host.enable_encrypt);
2812 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2813 }
2814 else
2815 host.enable = XSTRDUP (0, argv[0]);
2816
2817 return CMD_SUCCESS;
2818}
2819
2820ALIAS (config_enable_password,
2821 enable_password_text_cmd,
2822 "enable password LINE",
2823 "Modify enable password parameters\n"
2824 "Assign the privileged level password\n"
2825 "The UNENCRYPTED (cleartext) 'enable' password\n")
2826
2827/* VTY enable password delete. */
2828DEFUN (no_config_enable_password, no_enable_password_cmd,
2829 "no enable password",
2830 NO_STR
2831 "Modify enable password parameters\n"
2832 "Assign the privileged level password\n")
2833{
2834 if (host.enable)
2835 XFREE (0, host.enable);
2836 host.enable = NULL;
2837
2838 if (host.enable_encrypt)
2839 XFREE (0, host.enable_encrypt);
2840 host.enable_encrypt = NULL;
2841
2842 return CMD_SUCCESS;
2843}
2844
2845DEFUN (service_password_encrypt,
2846 service_password_encrypt_cmd,
2847 "service password-encryption",
2848 "Set up miscellaneous service\n"
2849 "Enable encrypted passwords\n")
2850{
2851 if (host.encrypt)
2852 return CMD_SUCCESS;
2853
2854 host.encrypt = 1;
2855
2856 if (host.password)
2857 {
2858 if (host.password_encrypt)
2859 XFREE (0, host.password_encrypt);
2860 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2861 }
2862 if (host.enable)
2863 {
2864 if (host.enable_encrypt)
2865 XFREE (0, host.enable_encrypt);
2866 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2867 }
2868
2869 return CMD_SUCCESS;
2870}
2871
2872DEFUN (no_service_password_encrypt,
2873 no_service_password_encrypt_cmd,
2874 "no service password-encryption",
2875 NO_STR
2876 "Set up miscellaneous service\n"
2877 "Enable encrypted passwords\n")
2878{
2879 if (! host.encrypt)
2880 return CMD_SUCCESS;
2881
2882 host.encrypt = 0;
2883
2884 if (host.password_encrypt)
2885 XFREE (0, host.password_encrypt);
2886 host.password_encrypt = NULL;
2887
2888 if (host.enable_encrypt)
2889 XFREE (0, host.enable_encrypt);
2890 host.enable_encrypt = NULL;
2891
2892 return CMD_SUCCESS;
2893}
2894
2895DEFUN (config_terminal_length, config_terminal_length_cmd,
2896 "terminal length <0-512>",
2897 "Set terminal line parameters\n"
2898 "Set number of lines on a screen\n"
2899 "Number of lines on screen (0 for no pausing)\n")
2900{
2901 int lines;
2902 char *endptr = NULL;
2903
2904 lines = strtol (argv[0], &endptr, 10);
2905 if (lines < 0 || lines > 512 || *endptr != '\0')
2906 {
2907 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2908 return CMD_WARNING;
2909 }
2910 vty->lines = lines;
2911
2912 return CMD_SUCCESS;
2913}
2914
2915DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2916 "terminal no length",
2917 "Set terminal line parameters\n"
2918 NO_STR
2919 "Set number of lines on a screen\n")
2920{
2921 vty->lines = -1;
2922 return CMD_SUCCESS;
2923}
2924
2925DEFUN (service_terminal_length, service_terminal_length_cmd,
2926 "service terminal-length <0-512>",
2927 "Set up miscellaneous service\n"
2928 "System wide terminal length configuration\n"
2929 "Number of lines of VTY (0 means no line control)\n")
2930{
2931 int lines;
2932 char *endptr = NULL;
2933
2934 lines = strtol (argv[0], &endptr, 10);
2935 if (lines < 0 || lines > 512 || *endptr != '\0')
2936 {
2937 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2938 return CMD_WARNING;
2939 }
2940 host.lines = lines;
2941
2942 return CMD_SUCCESS;
2943}
2944
2945DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2946 "no service terminal-length [<0-512>]",
2947 NO_STR
2948 "Set up miscellaneous service\n"
2949 "System wide terminal length configuration\n"
2950 "Number of lines of VTY (0 means no line control)\n")
2951{
2952 host.lines = -1;
2953 return CMD_SUCCESS;
2954}
2955
2956DEFUN (config_log_stdout,
2957 config_log_stdout_cmd,
2958 "log stdout",
2959 "Logging control\n"
2960 "Logging goes to stdout\n")
2961{
2962 zlog_set_flag (NULL, ZLOG_STDOUT);
2963 host.log_stdout = 1;
2964 return CMD_SUCCESS;
2965}
2966
2967DEFUN (no_config_log_stdout,
2968 no_config_log_stdout_cmd,
2969 "no log stdout",
2970 NO_STR
2971 "Logging control\n"
2972 "Cancel logging to stdout\n")
2973{
2974 zlog_reset_flag (NULL, ZLOG_STDOUT);
2975 host.log_stdout = 0;
2976 return CMD_SUCCESS;
2977}
2978
2979DEFUN (config_log_file,
2980 config_log_file_cmd,
2981 "log file FILENAME",
2982 "Logging control\n"
2983 "Logging to file\n"
2984 "Logging filename\n")
2985{
2986 int ret;
paul9035efa2004-10-10 11:56:56 +00002987 char *p = NULL;
2988 const char *fullpath;
2989
paul718e3742002-12-13 20:15:29 +00002990 /* Path detection. */
2991 if (! IS_DIRECTORY_SEP (*argv[0]))
2992 {
paul9035efa2004-10-10 11:56:56 +00002993 char cwd[MAXPATHLEN+1];
2994 cwd[MAXPATHLEN] = '\0';
2995
2996 if (getcwd (cwd, MAXPATHLEN) == NULL)
2997 {
2998 zlog_err ("config_log_file: Unable to alloc mem!");
2999 return CMD_WARNING;
3000 }
3001
3002 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (argv[0]) + 2))
3003 == NULL)
3004 {
3005 zlog_err ("config_log_file: Unable to alloc mem!");
3006 return CMD_WARNING;
3007 }
3008 sprintf (p, "%s/%s", cwd, argv[0]);
3009 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003010 }
3011 else
3012 fullpath = argv[0];
3013
3014 ret = zlog_set_file (NULL, ZLOG_FILE, fullpath);
3015
paul9035efa2004-10-10 11:56:56 +00003016 if (p)
3017 XFREE (MTYPE_TMP, p);
3018
paul718e3742002-12-13 20:15:29 +00003019 if (!ret)
3020 {
3021 vty_out (vty, "can't open logfile %s\n", argv[0]);
3022 return CMD_WARNING;
3023 }
3024
3025 if (host.logfile)
3026 XFREE (MTYPE_TMP, host.logfile);
3027
3028 host.logfile = strdup (argv[0]);
3029
3030 return CMD_SUCCESS;
3031}
3032
3033DEFUN (no_config_log_file,
3034 no_config_log_file_cmd,
3035 "no log file [FILENAME]",
3036 NO_STR
3037 "Logging control\n"
3038 "Cancel logging to file\n"
3039 "Logging file name\n")
3040{
3041 zlog_reset_file (NULL);
3042
3043 if (host.logfile)
3044 XFREE (MTYPE_TMP, host.logfile);
3045
3046 host.logfile = NULL;
3047
3048 return CMD_SUCCESS;
3049}
3050
3051DEFUN (config_log_syslog,
3052 config_log_syslog_cmd,
3053 "log syslog",
3054 "Logging control\n"
3055 "Logging goes to syslog\n")
3056{
3057 zlog_set_flag (NULL, ZLOG_SYSLOG);
3058 host.log_syslog = 1;
paul12ab19f2003-07-26 06:14:55 +00003059 zlog_default->facility = LOG_DAEMON;
3060 return CMD_SUCCESS;
3061}
3062
3063DEFUN (config_log_syslog_facility,
3064 config_log_syslog_facility_cmd,
3065 "log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3066 "Logging control\n"
3067 "Logging goes to syslog\n"
3068 "Facility parameter for syslog messages\n"
3069 "Kernel\n"
3070 "User process\n"
3071 "Mail system\n"
3072 "System daemons\n"
3073 "Authorization system\n"
3074 "Syslog itself\n"
3075 "Line printer system\n"
3076 "USENET news\n"
3077 "Unix-to-Unix copy system\n"
3078 "Cron/at facility\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 "Local use\n")
3087{
3088 int facility = LOG_DAEMON;
3089
3090 zlog_set_flag (NULL, ZLOG_SYSLOG);
3091 host.log_syslog = 1;
3092
3093 if (strncmp (argv[0], "kern", 1) == 0)
3094 facility = LOG_KERN;
3095 else if (strncmp (argv[0], "user", 2) == 0)
3096 facility = LOG_USER;
3097 else if (strncmp (argv[0], "mail", 1) == 0)
3098 facility = LOG_MAIL;
3099 else if (strncmp (argv[0], "daemon", 1) == 0)
3100 facility = LOG_DAEMON;
3101 else if (strncmp (argv[0], "auth", 1) == 0)
3102 facility = LOG_AUTH;
3103 else if (strncmp (argv[0], "syslog", 1) == 0)
3104 facility = LOG_SYSLOG;
3105 else if (strncmp (argv[0], "lpr", 2) == 0)
3106 facility = LOG_LPR;
3107 else if (strncmp (argv[0], "news", 1) == 0)
3108 facility = LOG_NEWS;
3109 else if (strncmp (argv[0], "uucp", 2) == 0)
3110 facility = LOG_UUCP;
3111 else if (strncmp (argv[0], "cron", 1) == 0)
3112 facility = LOG_CRON;
3113 else if (strncmp (argv[0], "local0", 6) == 0)
3114 facility = LOG_LOCAL0;
3115 else if (strncmp (argv[0], "local1", 6) == 0)
3116 facility = LOG_LOCAL1;
3117 else if (strncmp (argv[0], "local2", 6) == 0)
3118 facility = LOG_LOCAL2;
3119 else if (strncmp (argv[0], "local3", 6) == 0)
3120 facility = LOG_LOCAL3;
3121 else if (strncmp (argv[0], "local4", 6) == 0)
3122 facility = LOG_LOCAL4;
3123 else if (strncmp (argv[0], "local5", 6) == 0)
3124 facility = LOG_LOCAL5;
3125 else if (strncmp (argv[0], "local6", 6) == 0)
3126 facility = LOG_LOCAL6;
3127 else if (strncmp (argv[0], "local7", 6) == 0)
3128 facility = LOG_LOCAL7;
3129
3130 zlog_default->facility = facility;
3131
paul718e3742002-12-13 20:15:29 +00003132 return CMD_SUCCESS;
3133}
3134
3135DEFUN (no_config_log_syslog,
3136 no_config_log_syslog_cmd,
3137 "no log syslog",
3138 NO_STR
3139 "Logging control\n"
3140 "Cancel logging to syslog\n")
3141{
3142 zlog_reset_flag (NULL, ZLOG_SYSLOG);
3143 host.log_syslog = 0;
paul12ab19f2003-07-26 06:14:55 +00003144 zlog_default->facility = LOG_DAEMON;
paul718e3742002-12-13 20:15:29 +00003145 return CMD_SUCCESS;
3146}
3147
paul12ab19f2003-07-26 06:14:55 +00003148ALIAS (no_config_log_syslog,
3149 no_config_log_syslog_facility_cmd,
3150 "no log syslog facility (kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7)",
3151 NO_STR
3152 "Logging control\n"
3153 "Logging goes to syslog\n"
3154 "Facility parameter for syslog messages\n"
3155 "Kernel\n"
3156 "User process\n"
3157 "Mail system\n"
3158 "System daemons\n"
3159 "Authorization system\n"
3160 "Syslog itself\n"
3161 "Line printer system\n"
3162 "USENET news\n"
3163 "Unix-to-Unix copy system\n"
3164 "Cron/at facility\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 "Local use\n")
3173
paul718e3742002-12-13 20:15:29 +00003174DEFUN (config_log_trap,
3175 config_log_trap_cmd,
3176 "log trap (emergencies|alerts|critical|errors|warnings|notifications|informational|debugging)",
3177 "Logging control\n"
3178 "Limit logging to specifed level\n")
3179{
3180 int new_level ;
3181
3182 for ( new_level = 0 ; zlog_priority [new_level] != NULL ; new_level ++ )
3183 {
3184 if ( strcmp ( argv[0], zlog_priority [new_level] ) == 0 )
3185 /* found new logging level */
3186 {
3187 zlog_default->maskpri = new_level;
3188 return CMD_SUCCESS;
3189 }
3190 }
3191 return CMD_ERR_NO_MATCH;
3192}
3193
3194DEFUN (no_config_log_trap,
3195 no_config_log_trap_cmd,
3196 "no log trap",
3197 NO_STR
3198 "Logging control\n"
3199 "Permit all logging information\n")
3200{
3201 zlog_default->maskpri = LOG_DEBUG;
3202 return CMD_SUCCESS;
3203}
3204
3205DEFUN (config_log_record_priority,
3206 config_log_record_priority_cmd,
3207 "log record-priority",
3208 "Logging control\n"
3209 "Log the priority of the message within the message\n")
3210{
3211 zlog_default->record_priority = 1 ;
3212 return CMD_SUCCESS;
3213}
3214
3215DEFUN (no_config_log_record_priority,
3216 no_config_log_record_priority_cmd,
3217 "no log record-priority",
3218 NO_STR
3219 "Logging control\n"
3220 "Do not log the priority of the message within the message\n")
3221{
3222 zlog_default->record_priority = 0 ;
3223 return CMD_SUCCESS;
3224}
3225
3226
3227DEFUN (banner_motd_default,
3228 banner_motd_default_cmd,
3229 "banner motd default",
3230 "Set banner string\n"
3231 "Strings for motd\n"
3232 "Default string\n")
3233{
3234 host.motd = default_motd;
3235 return CMD_SUCCESS;
3236}
3237
3238DEFUN (no_banner_motd,
3239 no_banner_motd_cmd,
3240 "no banner motd",
3241 NO_STR
3242 "Set banner string\n"
3243 "Strings for motd\n")
3244{
3245 host.motd = NULL;
3246 return CMD_SUCCESS;
3247}
3248
3249/* Set config filename. Called from vty.c */
3250void
3251host_config_set (char *filename)
3252{
3253 host.config = strdup (filename);
3254}
3255
3256void
3257install_default (enum node_type node)
3258{
3259 install_element (node, &config_exit_cmd);
3260 install_element (node, &config_quit_cmd);
3261 install_element (node, &config_end_cmd);
3262 install_element (node, &config_help_cmd);
3263 install_element (node, &config_list_cmd);
3264
3265 install_element (node, &config_write_terminal_cmd);
3266 install_element (node, &config_write_file_cmd);
3267 install_element (node, &config_write_memory_cmd);
3268 install_element (node, &config_write_cmd);
3269 install_element (node, &show_running_config_cmd);
3270}
3271
3272/* Initialize command interface. Install basic nodes and commands. */
3273void
3274cmd_init (int terminal)
3275{
3276 /* Allocate initial top vector of commands. */
3277 cmdvec = vector_init (VECTOR_MIN_SIZE);
3278
3279 /* Default host value settings. */
3280 host.name = NULL;
3281 host.password = NULL;
3282 host.enable = NULL;
3283 host.logfile = NULL;
3284 host.config = NULL;
3285 host.lines = -1;
3286 host.motd = default_motd;
3287
3288 /* Install top nodes. */
3289 install_node (&view_node, NULL);
3290 install_node (&enable_node, NULL);
3291 install_node (&auth_node, NULL);
3292 install_node (&auth_enable_node, NULL);
3293 install_node (&config_node, config_write_host);
3294
3295 /* Each node's basic commands. */
3296 install_element (VIEW_NODE, &show_version_cmd);
3297 if (terminal)
3298 {
3299 install_element (VIEW_NODE, &config_list_cmd);
3300 install_element (VIEW_NODE, &config_exit_cmd);
3301 install_element (VIEW_NODE, &config_quit_cmd);
3302 install_element (VIEW_NODE, &config_help_cmd);
3303 install_element (VIEW_NODE, &config_enable_cmd);
3304 install_element (VIEW_NODE, &config_terminal_length_cmd);
3305 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
3306 }
3307
3308 if (terminal)
3309 {
3310 install_default (ENABLE_NODE);
3311 install_element (ENABLE_NODE, &config_disable_cmd);
3312 install_element (ENABLE_NODE, &config_terminal_cmd);
3313 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3314 }
3315 install_element (ENABLE_NODE, &show_startup_config_cmd);
3316 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003317
3318 if (terminal)
paul718e3742002-12-13 20:15:29 +00003319 {
hassoe7168df2004-10-03 20:11:32 +00003320 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3321 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
3322
3323 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003324 }
3325
3326 install_element (CONFIG_NODE, &hostname_cmd);
3327 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003328
hassoea8e9d92004-10-07 21:32:14 +00003329 if (terminal)
3330 {
hassoe7168df2004-10-03 20:11:32 +00003331 install_element (CONFIG_NODE, &password_cmd);
3332 install_element (CONFIG_NODE, &password_text_cmd);
3333 install_element (CONFIG_NODE, &enable_password_cmd);
3334 install_element (CONFIG_NODE, &enable_password_text_cmd);
3335 install_element (CONFIG_NODE, &no_enable_password_cmd);
3336
paul718e3742002-12-13 20:15:29 +00003337 install_element (CONFIG_NODE, &config_log_stdout_cmd);
3338 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
3339 install_element (CONFIG_NODE, &config_log_file_cmd);
3340 install_element (CONFIG_NODE, &no_config_log_file_cmd);
3341 install_element (CONFIG_NODE, &config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003342 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003343 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003344 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003345 install_element (CONFIG_NODE, &config_log_trap_cmd);
3346 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3347 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3348 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3349 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3350 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3351 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3352 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3353 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3354 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003355
paul9ab68122003-01-18 01:16:20 +00003356 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3357 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3358 }
paul718e3742002-12-13 20:15:29 +00003359 srand(time(NULL));
3360}