blob: 2766c4141e8baf48573cb3cb8e0846bf04030607 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
ajs2885f722004-12-17 23:16:33 +00002 $Id: command.c,v 1.30 2004/12/17 23:16:33 ajs Exp $
ajs274a4a42004-12-07 15:39:31 +00003
4 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00005 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
6
7This file is part of GNU Zebra.
8
9GNU Zebra is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published
11by the Free Software Foundation; either version 2, or (at your
12option) any later version.
13
14GNU Zebra is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU Zebra; see the file COPYING. If not, write to the
21Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
24#include <zebra.h>
25
paulb21b19c2003-06-15 01:28:29 +000026
paul718e3742002-12-13 20:15:29 +000027#include "memory.h"
28#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000029#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000030#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000031#include "vector.h"
32#include "vty.h"
33#include "command.h"
paul718e3742002-12-13 20:15:29 +000034
35/* Command vector which includes some level of command lists. Normally
36 each daemon maintains each own cmdvec. */
37vector cmdvec;
38
39/* Host information structure. */
40struct host host;
41
paul718e3742002-12-13 20:15:29 +000042/* Standard command node structures. */
43struct cmd_node auth_node =
44{
45 AUTH_NODE,
46 "Password: ",
47};
48
49struct cmd_node view_node =
50{
51 VIEW_NODE,
52 "%s> ",
53};
54
55struct cmd_node auth_enable_node =
56{
57 AUTH_ENABLE_NODE,
58 "Password: ",
59};
60
61struct cmd_node enable_node =
62{
63 ENABLE_NODE,
64 "%s# ",
65};
66
67struct cmd_node config_node =
68{
69 CONFIG_NODE,
70 "%s(config)# ",
71 1
72};
hasso6590f2c2004-10-19 20:40:08 +000073
74/* Default motd string. */
75const char *default_motd =
76"\r\n\
77Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
78" QUAGGA_COPYRIGHT "\r\n\
79\r\n";
80
ajs274a4a42004-12-07 15:39:31 +000081
82static struct facility_map {
83 int facility;
84 const char *name;
85 size_t match;
86} syslog_facilities[] =
87 {
88 { LOG_KERN, "kern", 1 },
89 { LOG_USER, "user", 2 },
90 { LOG_MAIL, "mail", 1 },
91 { LOG_DAEMON, "daemon", 1 },
92 { LOG_AUTH, "auth", 1 },
93 { LOG_SYSLOG, "syslog", 1 },
94 { LOG_LPR, "lpr", 2 },
95 { LOG_NEWS, "news", 1 },
96 { LOG_UUCP, "uucp", 2 },
97 { LOG_CRON, "cron", 1 },
98#ifdef LOG_FTP
99 { LOG_FTP, "ftp", 1 },
100#endif
101 { LOG_LOCAL0, "local0", 6 },
102 { LOG_LOCAL1, "local1", 6 },
103 { LOG_LOCAL2, "local2", 6 },
104 { LOG_LOCAL3, "local3", 6 },
105 { LOG_LOCAL4, "local4", 6 },
106 { LOG_LOCAL5, "local5", 6 },
107 { LOG_LOCAL6, "local6", 6 },
108 { LOG_LOCAL7, "local7", 6 },
109 { 0, NULL, 0 },
110 };
111
112static const char *
113facility_name(int facility)
114{
115 struct facility_map *fm;
116
117 for (fm = syslog_facilities; fm->name; fm++)
118 if (fm->facility == facility)
119 return fm->name;
120 return "";
121}
122
123static int
124facility_match(const char *str)
125{
126 struct facility_map *fm;
127
128 for (fm = syslog_facilities; fm->name; fm++)
129 if (!strncmp(str,fm->name,fm->match))
130 return fm->facility;
131 return -1;
132}
133
134static int
135level_match(const char *s)
136{
137 int level ;
138
139 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
140 if (!strncmp (s, zlog_priority[level], 2))
141 return level;
142 return ZLOG_DISABLED;
143}
144
hasso6590f2c2004-10-19 20:40:08 +0000145void
146print_version (const char *progname)
147{
148 printf ("%s version %s (%s)\n", progname, QUAGGA_VERSION, host.name);
149 printf ("%s\n", QUAGGA_COPYRIGHT);
150}
151
paul718e3742002-12-13 20:15:29 +0000152
153/* Utility function to concatenate argv argument into a single string
154 with inserting ' ' character between each argument. */
155char *
paul42d49862004-10-13 05:22:18 +0000156argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000157{
158 int i;
159 int len;
160 int index;
161 char *str;
162
163 str = NULL;
164 index = 0;
165
166 for (i = shift; i < argc; i++)
167 {
168 len = strlen (argv[i]);
169
170 if (i == shift)
171 {
172 str = XSTRDUP (MTYPE_TMP, argv[i]);
173 index = len;
174 }
175 else
176 {
177 str = XREALLOC (MTYPE_TMP, str, (index + len + 2));
178 str[index++] = ' ';
179 memcpy (str + index, argv[i], len);
180 index += len;
181 str[index] = '\0';
182 }
183 }
184 return str;
185}
186
187/* Install top node of command vector. */
188void
189install_node (struct cmd_node *node,
190 int (*func) (struct vty *))
191{
192 vector_set_index (cmdvec, node->node, node);
193 node->func = func;
194 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
195}
196
197/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000198static int
paul718e3742002-12-13 20:15:29 +0000199cmp_node (const void *p, const void *q)
200{
201 struct cmd_element *a = *(struct cmd_element **)p;
202 struct cmd_element *b = *(struct cmd_element **)q;
203
204 return strcmp (a->string, b->string);
205}
206
ajs274a4a42004-12-07 15:39:31 +0000207static int
paul718e3742002-12-13 20:15:29 +0000208cmp_desc (const void *p, const void *q)
209{
210 struct desc *a = *(struct desc **)p;
211 struct desc *b = *(struct desc **)q;
212
213 return strcmp (a->cmd, b->cmd);
214}
215
216/* Sort each node's command element according to command string. */
217void
218sort_node ()
219{
hasso8c328f12004-10-05 21:01:23 +0000220 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000221 struct cmd_node *cnode;
222 vector descvec;
223 struct cmd_element *cmd_element;
224
225 for (i = 0; i < vector_max (cmdvec); i++)
226 if ((cnode = vector_slot (cmdvec, i)) != NULL)
227 {
228 vector cmd_vector = cnode->cmd_vector;
229 qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
230
231 for (j = 0; j < vector_max (cmd_vector); j++)
232 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
233 {
234 descvec = vector_slot (cmd_element->strvec,
235 vector_max (cmd_element->strvec) - 1);
236 qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
237 }
238 }
239}
240
241/* Breaking up string into each command piece. I assume given
242 character is separated by a space character. Return value is a
243 vector which includes char ** data element. */
244vector
hassoea8e9d92004-10-07 21:32:14 +0000245cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000246{
hassoea8e9d92004-10-07 21:32:14 +0000247 const char *cp, *start;
248 char *token;
paul718e3742002-12-13 20:15:29 +0000249 int strlen;
250 vector strvec;
251
252 if (string == NULL)
253 return NULL;
254
255 cp = string;
256
257 /* Skip white spaces. */
258 while (isspace ((int) *cp) && *cp != '\0')
259 cp++;
260
261 /* Return if there is only white spaces */
262 if (*cp == '\0')
263 return NULL;
264
265 if (*cp == '!' || *cp == '#')
266 return NULL;
267
268 /* Prepare return vector. */
269 strvec = vector_init (VECTOR_MIN_SIZE);
270
271 /* Copy each command piece and set into vector. */
272 while (1)
273 {
274 start = cp;
275 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
276 *cp != '\0')
277 cp++;
278 strlen = cp - start;
279 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
280 memcpy (token, start, strlen);
281 *(token + strlen) = '\0';
282 vector_set (strvec, token);
283
284 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
285 *cp != '\0')
286 cp++;
287
288 if (*cp == '\0')
289 return strvec;
290 }
291}
292
293/* Free allocated string vector. */
294void
295cmd_free_strvec (vector v)
296{
hasso8c328f12004-10-05 21:01:23 +0000297 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000298 char *cp;
299
300 if (!v)
301 return;
302
303 for (i = 0; i < vector_max (v); i++)
304 if ((cp = vector_slot (v, i)) != NULL)
305 XFREE (MTYPE_STRVEC, cp);
306
307 vector_free (v);
308}
309
310/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000311static char *
hasso6ad96ea2004-10-07 19:33:46 +0000312cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000313{
hasso6ad96ea2004-10-07 19:33:46 +0000314 const char *cp, *start;
315 char *token;
paul718e3742002-12-13 20:15:29 +0000316 int strlen;
317
318 cp = *string;
319
320 if (cp == NULL)
321 return NULL;
322
323 /* Skip white spaces. */
324 while (isspace ((int) *cp) && *cp != '\0')
325 cp++;
326
327 /* Return if there is only white spaces */
328 if (*cp == '\0')
329 return NULL;
330
331 start = cp;
332
333 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
334 cp++;
335
336 strlen = cp - start;
337 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
338 memcpy (token, start, strlen);
339 *(token + strlen) = '\0';
340
341 *string = cp;
342
343 return token;
344}
345
346/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000347static vector
hasso8c328f12004-10-05 21:01:23 +0000348cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000349{
350 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000351 const char *sp;
paul718e3742002-12-13 20:15:29 +0000352 char *token;
353 int len;
hasso8c328f12004-10-05 21:01:23 +0000354 const char *cp;
355 const char *dp;
paul718e3742002-12-13 20:15:29 +0000356 vector allvec;
357 vector strvec = NULL;
358 struct desc *desc;
359
360 cp = string;
361 dp = descstr;
362
363 if (cp == NULL)
364 return NULL;
365
366 allvec = vector_init (VECTOR_MIN_SIZE);
367
368 while (1)
369 {
370 while (isspace ((int) *cp) && *cp != '\0')
371 cp++;
372
373 if (*cp == '(')
374 {
375 multiple = 1;
376 cp++;
377 }
378 if (*cp == ')')
379 {
380 multiple = 0;
381 cp++;
382 }
383 if (*cp == '|')
384 {
385 if (! multiple)
386 {
387 fprintf (stderr, "Command parse error!: %s\n", string);
388 exit (1);
389 }
390 cp++;
391 }
392
393 while (isspace ((int) *cp) && *cp != '\0')
394 cp++;
395
396 if (*cp == '(')
397 {
398 multiple = 1;
399 cp++;
400 }
401
402 if (*cp == '\0')
403 return allvec;
404
405 sp = cp;
406
407 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
408 cp++;
409
410 len = cp - sp;
411
412 token = XMALLOC (MTYPE_STRVEC, len + 1);
413 memcpy (token, sp, len);
414 *(token + len) = '\0';
415
416 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
417 desc->cmd = token;
418 desc->str = cmd_desc_str (&dp);
419
420 if (multiple)
421 {
422 if (multiple == 1)
423 {
424 strvec = vector_init (VECTOR_MIN_SIZE);
425 vector_set (allvec, strvec);
426 }
427 multiple++;
428 }
429 else
430 {
431 strvec = vector_init (VECTOR_MIN_SIZE);
432 vector_set (allvec, strvec);
433 }
434 vector_set (strvec, desc);
435 }
436}
437
438/* Count mandantory string vector size. This is to determine inputed
439 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000440static int
paul718e3742002-12-13 20:15:29 +0000441cmd_cmdsize (vector strvec)
442{
hasso8c328f12004-10-05 21:01:23 +0000443 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000444 int size = 0;
445 vector descvec;
446
447 for (i = 0; i < vector_max (strvec); i++)
448 {
449 descvec = vector_slot (strvec, i);
450
451 if (vector_max (descvec) == 1)
452 {
453 struct desc *desc = vector_slot (descvec, 0);
454
hasso8c328f12004-10-05 21:01:23 +0000455 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000456 return size;
457 else
458 size++;
459 }
460 else
461 size++;
462 }
463 return size;
464}
465
466/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000467const char *
paul718e3742002-12-13 20:15:29 +0000468cmd_prompt (enum node_type node)
469{
470 struct cmd_node *cnode;
471
472 cnode = vector_slot (cmdvec, node);
473 return cnode->prompt;
474}
475
476/* Install a command into a node. */
477void
478install_element (enum node_type ntype, struct cmd_element *cmd)
479{
480 struct cmd_node *cnode;
481
482 cnode = vector_slot (cmdvec, ntype);
483
484 if (cnode == NULL)
485 {
486 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
487 ntype);
488 exit (1);
489 }
490
491 vector_set (cnode->cmd_vector, cmd);
492
493 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
494 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
495}
496
497static unsigned char itoa64[] =
498"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
499
ajs274a4a42004-12-07 15:39:31 +0000500static void
paul718e3742002-12-13 20:15:29 +0000501to64(char *s, long v, int n)
502{
503 while (--n >= 0)
504 {
505 *s++ = itoa64[v&0x3f];
506 v >>= 6;
507 }
508}
509
ajs274a4a42004-12-07 15:39:31 +0000510static char *
511zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000512{
513 char salt[6];
514 struct timeval tv;
515 char *crypt (const char *, const char *);
516
517 gettimeofday(&tv,0);
518
519 to64(&salt[0], random(), 3);
520 to64(&salt[3], tv.tv_usec, 3);
521 salt[5] = '\0';
522
523 return crypt (passwd, salt);
524}
525
526/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000527static int
paul718e3742002-12-13 20:15:29 +0000528config_write_host (struct vty *vty)
529{
530 if (host.name)
531 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
532
533 if (host.encrypt)
534 {
535 if (host.password_encrypt)
536 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
537 if (host.enable_encrypt)
538 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
539 }
540 else
541 {
542 if (host.password)
543 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
544 if (host.enable)
545 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
546 }
547
ajs274a4a42004-12-07 15:39:31 +0000548 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000549 {
550 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
551 VTY_NEWLINE);
552 vty_out (vty, "log trap %s%s",
553 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
554 }
paul718e3742002-12-13 20:15:29 +0000555
ajs274a4a42004-12-07 15:39:31 +0000556 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000557 {
ajs274a4a42004-12-07 15:39:31 +0000558 vty_out (vty, "log file %s", host.logfile);
559 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
560 vty_out (vty, " %s",
561 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000562 vty_out (vty, "%s", VTY_NEWLINE);
563 }
ajs274a4a42004-12-07 15:39:31 +0000564
565 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
566 {
567 vty_out (vty, "log stdout");
568 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
569 vty_out (vty, " %s",
570 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
571 vty_out (vty, "%s", VTY_NEWLINE);
572 }
573
574 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
575 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
576 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
577 vty_out(vty,"log monitor %s%s",
578 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
579
580 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
581 {
582 vty_out (vty, "log syslog");
583 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
584 vty_out (vty, " %s",
585 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
586 vty_out (vty, "%s", VTY_NEWLINE);
587 }
588
589 if (zlog_default->facility != LOG_DAEMON)
590 vty_out (vty, "log facility %s%s",
591 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000592
593 if (zlog_default->record_priority == 1)
594 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
595
596 if (host.advanced)
597 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
598
599 if (host.encrypt)
600 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
601
602 if (host.lines >= 0)
603 vty_out (vty, "service terminal-length %d%s", host.lines,
604 VTY_NEWLINE);
605
606 if (! host.motd)
607 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
608
609 return 1;
610}
611
612/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000613static vector
paul718e3742002-12-13 20:15:29 +0000614cmd_node_vector (vector v, enum node_type ntype)
615{
616 struct cmd_node *cnode = vector_slot (v, ntype);
617 return cnode->cmd_vector;
618}
619
ajs274a4a42004-12-07 15:39:31 +0000620#if 0
621/* Filter command vector by symbol. This function is not actually used;
622 * should it be deleted? */
623static int
paul718e3742002-12-13 20:15:29 +0000624cmd_filter_by_symbol (char *command, char *symbol)
625{
626 int i, lim;
627
628 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
629 {
630 i = 0;
631 lim = strlen (command);
632 while (i < lim)
633 {
634 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
635 return 1;
636 i++;
637 }
638 return 0;
639 }
640 if (strcmp (symbol, "STRING") == 0)
641 {
642 i = 0;
643 lim = strlen (command);
644 while (i < lim)
645 {
646 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
647 return 1;
648 i++;
649 }
650 return 0;
651 }
652 if (strcmp (symbol, "IFNAME") == 0)
653 {
654 i = 0;
655 lim = strlen (command);
656 while (i < lim)
657 {
658 if (! isalnum ((int) command[i]))
659 return 1;
660 i++;
661 }
662 return 0;
663 }
664 return 0;
665}
ajs274a4a42004-12-07 15:39:31 +0000666#endif
paul718e3742002-12-13 20:15:29 +0000667
668/* Completion match types. */
669enum match_type
670{
671 no_match,
672 extend_match,
673 ipv4_prefix_match,
674 ipv4_match,
675 ipv6_prefix_match,
676 ipv6_match,
677 range_match,
678 vararg_match,
679 partly_match,
680 exact_match
681};
682
ajs274a4a42004-12-07 15:39:31 +0000683static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000684cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000685{
hasso8c328f12004-10-05 21:01:23 +0000686 const char *sp;
paul718e3742002-12-13 20:15:29 +0000687 int dots = 0, nums = 0;
688 char buf[4];
689
690 if (str == NULL)
691 return partly_match;
692
693 for (;;)
694 {
695 memset (buf, 0, sizeof (buf));
696 sp = str;
697 while (*str != '\0')
698 {
699 if (*str == '.')
700 {
701 if (dots >= 3)
702 return no_match;
703
704 if (*(str + 1) == '.')
705 return no_match;
706
707 if (*(str + 1) == '\0')
708 return partly_match;
709
710 dots++;
711 break;
712 }
713 if (!isdigit ((int) *str))
714 return no_match;
715
716 str++;
717 }
718
719 if (str - sp > 3)
720 return no_match;
721
722 strncpy (buf, sp, str - sp);
723 if (atoi (buf) > 255)
724 return no_match;
725
726 nums++;
727
728 if (*str == '\0')
729 break;
730
731 str++;
732 }
733
734 if (nums < 4)
735 return partly_match;
736
737 return exact_match;
738}
739
ajs274a4a42004-12-07 15:39:31 +0000740static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000741cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000742{
hasso8c328f12004-10-05 21:01:23 +0000743 const char *sp;
paul718e3742002-12-13 20:15:29 +0000744 int dots = 0;
745 char buf[4];
746
747 if (str == NULL)
748 return partly_match;
749
750 for (;;)
751 {
752 memset (buf, 0, sizeof (buf));
753 sp = str;
754 while (*str != '\0' && *str != '/')
755 {
756 if (*str == '.')
757 {
758 if (dots == 3)
759 return no_match;
760
761 if (*(str + 1) == '.' || *(str + 1) == '/')
762 return no_match;
763
764 if (*(str + 1) == '\0')
765 return partly_match;
766
767 dots++;
768 break;
769 }
770
771 if (!isdigit ((int) *str))
772 return no_match;
773
774 str++;
775 }
776
777 if (str - sp > 3)
778 return no_match;
779
780 strncpy (buf, sp, str - sp);
781 if (atoi (buf) > 255)
782 return no_match;
783
784 if (dots == 3)
785 {
786 if (*str == '/')
787 {
788 if (*(str + 1) == '\0')
789 return partly_match;
790
791 str++;
792 break;
793 }
794 else if (*str == '\0')
795 return partly_match;
796 }
797
798 if (*str == '\0')
799 return partly_match;
800
801 str++;
802 }
803
804 sp = str;
805 while (*str != '\0')
806 {
807 if (!isdigit ((int) *str))
808 return no_match;
809
810 str++;
811 }
812
813 if (atoi (sp) > 32)
814 return no_match;
815
816 return exact_match;
817}
818
819#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
820#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
821#define STATE_START 1
822#define STATE_COLON 2
823#define STATE_DOUBLE 3
824#define STATE_ADDR 4
825#define STATE_DOT 5
826#define STATE_SLASH 6
827#define STATE_MASK 7
828
paul22e0a9e2003-07-11 17:55:46 +0000829#ifdef HAVE_IPV6
830
ajs274a4a42004-12-07 15:39:31 +0000831static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000832cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000833{
834 int state = STATE_START;
835 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000836 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000837 struct sockaddr_in6 sin6_dummy;
838 int ret;
paul718e3742002-12-13 20:15:29 +0000839
840 if (str == NULL)
841 return partly_match;
842
843 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
844 return no_match;
845
hasso726f9b22003-05-25 21:04:54 +0000846 /* use inet_pton that has a better support,
847 * for example inet_pton can support the automatic addresses:
848 * ::1.2.3.4
849 */
850 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
851
852 if (ret == 1)
853 return exact_match;
854
paul718e3742002-12-13 20:15:29 +0000855 while (*str != '\0')
856 {
857 switch (state)
858 {
859 case STATE_START:
860 if (*str == ':')
861 {
862 if (*(str + 1) != ':' && *(str + 1) != '\0')
863 return no_match;
864 colons--;
865 state = STATE_COLON;
866 }
867 else
868 {
869 sp = str;
870 state = STATE_ADDR;
871 }
872
873 continue;
874 case STATE_COLON:
875 colons++;
876 if (*(str + 1) == ':')
877 state = STATE_DOUBLE;
878 else
879 {
880 sp = str + 1;
881 state = STATE_ADDR;
882 }
883 break;
884 case STATE_DOUBLE:
885 if (double_colon)
886 return no_match;
887
888 if (*(str + 1) == ':')
889 return no_match;
890 else
891 {
892 if (*(str + 1) != '\0')
893 colons++;
894 sp = str + 1;
895 state = STATE_ADDR;
896 }
897
898 double_colon++;
899 nums++;
900 break;
901 case STATE_ADDR:
902 if (*(str + 1) == ':' || *(str + 1) == '\0')
903 {
904 if (str - sp > 3)
905 return no_match;
906
907 nums++;
908 state = STATE_COLON;
909 }
910 if (*(str + 1) == '.')
911 state = STATE_DOT;
912 break;
913 case STATE_DOT:
914 state = STATE_ADDR;
915 break;
916 default:
917 break;
918 }
919
920 if (nums > 8)
921 return no_match;
922
923 if (colons > 7)
924 return no_match;
925
926 str++;
927 }
928
929#if 0
930 if (nums < 11)
931 return partly_match;
932#endif /* 0 */
933
934 return exact_match;
935}
936
ajs274a4a42004-12-07 15:39:31 +0000937static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000938cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000939{
940 int state = STATE_START;
941 int colons = 0, nums = 0, double_colon = 0;
942 int mask;
hasso8c328f12004-10-05 21:01:23 +0000943 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000944 char *endptr = NULL;
945
946 if (str == NULL)
947 return partly_match;
948
949 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
950 return no_match;
951
952 while (*str != '\0' && state != STATE_MASK)
953 {
954 switch (state)
955 {
956 case STATE_START:
957 if (*str == ':')
958 {
959 if (*(str + 1) != ':' && *(str + 1) != '\0')
960 return no_match;
961 colons--;
962 state = STATE_COLON;
963 }
964 else
965 {
966 sp = str;
967 state = STATE_ADDR;
968 }
969
970 continue;
971 case STATE_COLON:
972 colons++;
973 if (*(str + 1) == '/')
974 return no_match;
975 else if (*(str + 1) == ':')
976 state = STATE_DOUBLE;
977 else
978 {
979 sp = str + 1;
980 state = STATE_ADDR;
981 }
982 break;
983 case STATE_DOUBLE:
984 if (double_colon)
985 return no_match;
986
987 if (*(str + 1) == ':')
988 return no_match;
989 else
990 {
991 if (*(str + 1) != '\0' && *(str + 1) != '/')
992 colons++;
993 sp = str + 1;
994
995 if (*(str + 1) == '/')
996 state = STATE_SLASH;
997 else
998 state = STATE_ADDR;
999 }
1000
1001 double_colon++;
1002 nums += 1;
1003 break;
1004 case STATE_ADDR:
1005 if (*(str + 1) == ':' || *(str + 1) == '.'
1006 || *(str + 1) == '\0' || *(str + 1) == '/')
1007 {
1008 if (str - sp > 3)
1009 return no_match;
1010
1011 for (; sp <= str; sp++)
1012 if (*sp == '/')
1013 return no_match;
1014
1015 nums++;
1016
1017 if (*(str + 1) == ':')
1018 state = STATE_COLON;
1019 else if (*(str + 1) == '.')
1020 state = STATE_DOT;
1021 else if (*(str + 1) == '/')
1022 state = STATE_SLASH;
1023 }
1024 break;
1025 case STATE_DOT:
1026 state = STATE_ADDR;
1027 break;
1028 case STATE_SLASH:
1029 if (*(str + 1) == '\0')
1030 return partly_match;
1031
1032 state = STATE_MASK;
1033 break;
1034 default:
1035 break;
1036 }
1037
1038 if (nums > 11)
1039 return no_match;
1040
1041 if (colons > 7)
1042 return no_match;
1043
1044 str++;
1045 }
1046
1047 if (state < STATE_MASK)
1048 return partly_match;
1049
1050 mask = strtol (str, &endptr, 10);
1051 if (*endptr != '\0')
1052 return no_match;
1053
1054 if (mask < 0 || mask > 128)
1055 return no_match;
1056
1057/* I don't know why mask < 13 makes command match partly.
1058 Forgive me to make this comments. I Want to set static default route
1059 because of lack of function to originate default in ospf6d; sorry
1060 yasu
1061 if (mask < 13)
1062 return partly_match;
1063*/
1064
1065 return exact_match;
1066}
1067
paul22e0a9e2003-07-11 17:55:46 +00001068#endif /* HAVE_IPV6 */
1069
paul718e3742002-12-13 20:15:29 +00001070#define DECIMAL_STRLEN_MAX 10
1071
ajs274a4a42004-12-07 15:39:31 +00001072static int
hasso8c328f12004-10-05 21:01:23 +00001073cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001074{
1075 char *p;
1076 char buf[DECIMAL_STRLEN_MAX + 1];
1077 char *endptr = NULL;
1078 unsigned long min, max, val;
1079
1080 if (str == NULL)
1081 return 1;
1082
1083 val = strtoul (str, &endptr, 10);
1084 if (*endptr != '\0')
1085 return 0;
1086
1087 range++;
1088 p = strchr (range, '-');
1089 if (p == NULL)
1090 return 0;
1091 if (p - range > DECIMAL_STRLEN_MAX)
1092 return 0;
1093 strncpy (buf, range, p - range);
1094 buf[p - range] = '\0';
1095 min = strtoul (buf, &endptr, 10);
1096 if (*endptr != '\0')
1097 return 0;
1098
1099 range = p + 1;
1100 p = strchr (range, '>');
1101 if (p == NULL)
1102 return 0;
1103 if (p - range > DECIMAL_STRLEN_MAX)
1104 return 0;
1105 strncpy (buf, range, p - range);
1106 buf[p - range] = '\0';
1107 max = strtoul (buf, &endptr, 10);
1108 if (*endptr != '\0')
1109 return 0;
1110
1111 if (val < min || val > max)
1112 return 0;
1113
1114 return 1;
1115}
1116
1117/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001118static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001119cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001120{
hasso8c328f12004-10-05 21:01:23 +00001121 unsigned int i;
1122 const char *str;
paul718e3742002-12-13 20:15:29 +00001123 struct cmd_element *cmd_element;
1124 enum match_type match_type;
1125 vector descvec;
1126 struct desc *desc;
1127
1128 match_type = no_match;
1129
1130 /* If command and cmd_element string does not match set NULL to vector */
1131 for (i = 0; i < vector_max (v); i++)
1132 if ((cmd_element = vector_slot (v, i)) != NULL)
1133 {
1134 if (index >= vector_max (cmd_element->strvec))
1135 vector_slot (v, i) = NULL;
1136 else
1137 {
hasso8c328f12004-10-05 21:01:23 +00001138 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001139 int matched = 0;
1140
1141 descvec = vector_slot (cmd_element->strvec, index);
1142
1143 for (j = 0; j < vector_max (descvec); j++)
1144 {
1145 desc = vector_slot (descvec, j);
1146 str = desc->cmd;
1147
1148 if (CMD_VARARG (str))
1149 {
1150 if (match_type < vararg_match)
1151 match_type = vararg_match;
1152 matched++;
1153 }
1154 else if (CMD_RANGE (str))
1155 {
1156 if (cmd_range_match (str, command))
1157 {
1158 if (match_type < range_match)
1159 match_type = range_match;
1160
1161 matched++;
1162 }
1163 }
paul22e0a9e2003-07-11 17:55:46 +00001164#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001165 else if (CMD_IPV6 (str))
1166 {
1167 if (cmd_ipv6_match (command))
1168 {
1169 if (match_type < ipv6_match)
1170 match_type = ipv6_match;
1171
1172 matched++;
1173 }
1174 }
1175 else if (CMD_IPV6_PREFIX (str))
1176 {
1177 if (cmd_ipv6_prefix_match (command))
1178 {
1179 if (match_type < ipv6_prefix_match)
1180 match_type = ipv6_prefix_match;
1181
1182 matched++;
1183 }
1184 }
paul22e0a9e2003-07-11 17:55:46 +00001185#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001186 else if (CMD_IPV4 (str))
1187 {
1188 if (cmd_ipv4_match (command))
1189 {
1190 if (match_type < ipv4_match)
1191 match_type = ipv4_match;
1192
1193 matched++;
1194 }
1195 }
1196 else if (CMD_IPV4_PREFIX (str))
1197 {
1198 if (cmd_ipv4_prefix_match (command))
1199 {
1200 if (match_type < ipv4_prefix_match)
1201 match_type = ipv4_prefix_match;
1202 matched++;
1203 }
1204 }
1205 else
1206 /* Check is this point's argument optional ? */
1207 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1208 {
1209 if (match_type < extend_match)
1210 match_type = extend_match;
1211 matched++;
1212 }
1213 else if (strncmp (command, str, strlen (command)) == 0)
1214 {
1215 if (strcmp (command, str) == 0)
1216 match_type = exact_match;
1217 else
1218 {
1219 if (match_type < partly_match)
1220 match_type = partly_match;
1221 }
1222 matched++;
1223 }
1224 }
1225 if (! matched)
1226 vector_slot (v, i) = NULL;
1227 }
1228 }
1229 return match_type;
1230}
1231
1232/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001233static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001234cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001235{
hasso8c328f12004-10-05 21:01:23 +00001236 unsigned int i;
1237 const char *str;
paul718e3742002-12-13 20:15:29 +00001238 struct cmd_element *cmd_element;
1239 enum match_type match_type;
1240 vector descvec;
1241 struct desc *desc;
1242
1243 match_type = no_match;
1244
1245 /* If command and cmd_element string does not match set NULL to vector */
1246 for (i = 0; i < vector_max (v); i++)
1247 if ((cmd_element = vector_slot (v, i)) != NULL)
1248 {
1249 /* If given index is bigger than max string vector of command,
1250 set NULL*/
1251 if (index >= vector_max (cmd_element->strvec))
1252 vector_slot (v, i) = NULL;
1253 else
1254 {
hasso8c328f12004-10-05 21:01:23 +00001255 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001256 int matched = 0;
1257
1258 descvec = vector_slot (cmd_element->strvec, index);
1259
1260 for (j = 0; j < vector_max (descvec); j++)
1261 {
1262 desc = vector_slot (descvec, j);
1263 str = desc->cmd;
1264
1265 if (CMD_VARARG (str))
1266 {
1267 if (match_type < vararg_match)
1268 match_type = vararg_match;
1269 matched++;
1270 }
1271 else if (CMD_RANGE (str))
1272 {
1273 if (cmd_range_match (str, command))
1274 {
1275 if (match_type < range_match)
1276 match_type = range_match;
1277 matched++;
1278 }
1279 }
paul22e0a9e2003-07-11 17:55:46 +00001280#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001281 else if (CMD_IPV6 (str))
1282 {
1283 if (cmd_ipv6_match (command) == exact_match)
1284 {
1285 if (match_type < ipv6_match)
1286 match_type = ipv6_match;
1287 matched++;
1288 }
1289 }
1290 else if (CMD_IPV6_PREFIX (str))
1291 {
1292 if (cmd_ipv6_prefix_match (command) == exact_match)
1293 {
1294 if (match_type < ipv6_prefix_match)
1295 match_type = ipv6_prefix_match;
1296 matched++;
1297 }
1298 }
paul22e0a9e2003-07-11 17:55:46 +00001299#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001300 else if (CMD_IPV4 (str))
1301 {
1302 if (cmd_ipv4_match (command) == exact_match)
1303 {
1304 if (match_type < ipv4_match)
1305 match_type = ipv4_match;
1306 matched++;
1307 }
1308 }
1309 else if (CMD_IPV4_PREFIX (str))
1310 {
1311 if (cmd_ipv4_prefix_match (command) == exact_match)
1312 {
1313 if (match_type < ipv4_prefix_match)
1314 match_type = ipv4_prefix_match;
1315 matched++;
1316 }
1317 }
1318 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1319 {
1320 if (match_type < extend_match)
1321 match_type = extend_match;
1322 matched++;
1323 }
1324 else
1325 {
1326 if (strcmp (command, str) == 0)
1327 {
1328 match_type = exact_match;
1329 matched++;
1330 }
1331 }
1332 }
1333 if (! matched)
1334 vector_slot (v, i) = NULL;
1335 }
1336 }
1337 return match_type;
1338}
1339
1340/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001341static int
paul718e3742002-12-13 20:15:29 +00001342is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1343{
hasso8c328f12004-10-05 21:01:23 +00001344 unsigned int i;
1345 unsigned int j;
1346 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001347 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001348 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001349 vector descvec;
1350 struct desc *desc;
1351
1352 for (i = 0; i < vector_max (v); i++)
1353 if ((cmd_element = vector_slot (v, i)) != NULL)
1354 {
1355 int match = 0;
1356
1357 descvec = vector_slot (cmd_element->strvec, index);
1358
1359 for (j = 0; j < vector_max (descvec); j++)
1360 {
1361 enum match_type ret;
1362
1363 desc = vector_slot (descvec, j);
1364 str = desc->cmd;
1365
1366 switch (type)
1367 {
1368 case exact_match:
1369 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1370 && strcmp (command, str) == 0)
1371 match++;
1372 break;
1373 case partly_match:
1374 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1375 && strncmp (command, str, strlen (command)) == 0)
1376 {
1377 if (matched && strcmp (matched, str) != 0)
1378 return 1; /* There is ambiguous match. */
1379 else
1380 matched = str;
1381 match++;
1382 }
1383 break;
1384 case range_match:
1385 if (cmd_range_match (str, command))
1386 {
1387 if (matched && strcmp (matched, str) != 0)
1388 return 1;
1389 else
1390 matched = str;
1391 match++;
1392 }
1393 break;
paul22e0a9e2003-07-11 17:55:46 +00001394#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001395 case ipv6_match:
1396 if (CMD_IPV6 (str))
1397 match++;
1398 break;
1399 case ipv6_prefix_match:
1400 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1401 {
1402 if (ret == partly_match)
1403 return 2; /* There is incomplete match. */
1404
1405 match++;
1406 }
1407 break;
paul22e0a9e2003-07-11 17:55:46 +00001408#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001409 case ipv4_match:
1410 if (CMD_IPV4 (str))
1411 match++;
1412 break;
1413 case ipv4_prefix_match:
1414 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1415 {
1416 if (ret == partly_match)
1417 return 2; /* There is incomplete match. */
1418
1419 match++;
1420 }
1421 break;
1422 case extend_match:
1423 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1424 match++;
1425 break;
1426 case no_match:
1427 default:
1428 break;
1429 }
1430 }
1431 if (! match)
1432 vector_slot (v, i) = NULL;
1433 }
1434 return 0;
1435}
1436
1437/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001438static const char *
hasso8c328f12004-10-05 21:01:23 +00001439cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001440{
1441 /* Skip variable arguments. */
1442 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1443 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1444 return NULL;
1445
1446 /* In case of 'command \t', given src is NULL string. */
1447 if (src == NULL)
1448 return dst;
1449
1450 /* Matched with input string. */
1451 if (strncmp (src, dst, strlen (src)) == 0)
1452 return dst;
1453
1454 return NULL;
1455}
1456
1457/* If src matches dst return dst string, otherwise return NULL */
1458/* This version will return the dst string always if it is
1459 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001460static const char *
hasso8c328f12004-10-05 21:01:23 +00001461cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001462{
1463 if (CMD_VARARG (dst))
1464 return dst;
1465
1466 if (CMD_RANGE (dst))
1467 {
1468 if (cmd_range_match (dst, src))
1469 return dst;
1470 else
1471 return NULL;
1472 }
1473
paul22e0a9e2003-07-11 17:55:46 +00001474#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001475 if (CMD_IPV6 (dst))
1476 {
1477 if (cmd_ipv6_match (src))
1478 return dst;
1479 else
1480 return NULL;
1481 }
1482
1483 if (CMD_IPV6_PREFIX (dst))
1484 {
1485 if (cmd_ipv6_prefix_match (src))
1486 return dst;
1487 else
1488 return NULL;
1489 }
paul22e0a9e2003-07-11 17:55:46 +00001490#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001491
1492 if (CMD_IPV4 (dst))
1493 {
1494 if (cmd_ipv4_match (src))
1495 return dst;
1496 else
1497 return NULL;
1498 }
1499
1500 if (CMD_IPV4_PREFIX (dst))
1501 {
1502 if (cmd_ipv4_prefix_match (src))
1503 return dst;
1504 else
1505 return NULL;
1506 }
1507
1508 /* Optional or variable commands always match on '?' */
1509 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1510 return dst;
1511
1512 /* In case of 'command \t', given src is NULL string. */
1513 if (src == NULL)
1514 return dst;
1515
1516 if (strncmp (src, dst, strlen (src)) == 0)
1517 return dst;
1518 else
1519 return NULL;
1520}
1521
1522/* Check same string element existence. If it isn't there return
1523 1. */
ajs274a4a42004-12-07 15:39:31 +00001524static int
hasso8c328f12004-10-05 21:01:23 +00001525cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001526{
hasso8c328f12004-10-05 21:01:23 +00001527 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001528 char *match;
1529
1530 for (i = 0; i < vector_max (v); i++)
1531 if ((match = vector_slot (v, i)) != NULL)
1532 if (strcmp (match, str) == 0)
1533 return 0;
1534 return 1;
1535}
1536
1537/* Compare string to description vector. If there is same string
1538 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001539static int
hasso8c328f12004-10-05 21:01:23 +00001540desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001541{
hasso8c328f12004-10-05 21:01:23 +00001542 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001543 struct desc *desc;
1544
1545 for (i = 0; i < vector_max (v); i++)
1546 if ((desc = vector_slot (v, i)) != NULL)
1547 if (strcmp (desc->cmd, str) == 0)
1548 return 1;
1549 return 0;
1550}
1551
ajs274a4a42004-12-07 15:39:31 +00001552static int
paulb92938a2002-12-13 21:20:42 +00001553cmd_try_do_shortcut (enum node_type node, char* first_word) {
1554 if ( first_word != NULL &&
1555 node != AUTH_NODE &&
1556 node != VIEW_NODE &&
1557 node != AUTH_ENABLE_NODE &&
1558 node != ENABLE_NODE &&
1559 0 == strcmp( "do", first_word ) )
1560 return 1;
1561 return 0;
1562}
1563
paul718e3742002-12-13 20:15:29 +00001564/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001565static vector
paulb92938a2002-12-13 21:20:42 +00001566cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001567{
hasso8c328f12004-10-05 21:01:23 +00001568 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001569 vector cmd_vector;
1570#define INIT_MATCHVEC_SIZE 10
1571 vector matchvec;
1572 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001573 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001574 int ret;
1575 enum match_type match;
1576 char *command;
paul718e3742002-12-13 20:15:29 +00001577 static struct desc desc_cr = { "<cr>", "" };
1578
1579 /* Set index. */
1580 index = vector_max (vline) - 1;
1581
1582 /* Make copy vector of current node's command vector. */
1583 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1584
1585 /* Prepare match vector */
1586 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1587
1588 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001589 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001590 for (i = 0; i < index; i++)
1591 {
paul718e3742002-12-13 20:15:29 +00001592 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00001593 match = cmd_filter_by_completion (command, cmd_vector, i);
1594
1595 if (match == vararg_match)
1596 {
1597 struct cmd_element *cmd_element;
1598 vector descvec;
hasso8c328f12004-10-05 21:01:23 +00001599 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001600
1601 for (j = 0; j < vector_max (cmd_vector); j++)
1602 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1603 {
1604 descvec = vector_slot (cmd_element->strvec,
1605 vector_max (cmd_element->strvec) - 1);
1606 for (k = 0; k < vector_max (descvec); k++)
1607 {
1608 struct desc *desc = vector_slot (descvec, k);
1609 vector_set (matchvec, desc);
1610 }
1611 }
1612
1613 vector_set (matchvec, &desc_cr);
paul718e3742002-12-13 20:15:29 +00001614 vector_free (cmd_vector);
1615
1616 return matchvec;
1617 }
1618
1619 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1620 {
1621 vector_free (cmd_vector);
1622 *status = CMD_ERR_AMBIGUOUS;
1623 return NULL;
1624 }
1625 else if (ret == 2)
1626 {
1627 vector_free (cmd_vector);
1628 *status = CMD_ERR_NO_MATCH;
1629 return NULL;
1630 }
1631 }
1632
1633 /* Prepare match vector */
1634 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1635
paul54aba542003-08-21 20:28:24 +00001636 /* Make sure that cmd_vector is filtered based on current word */
1637 command = vector_slot (vline, index);
1638 if (command)
1639 match = cmd_filter_by_completion (command, cmd_vector, index);
1640
paul718e3742002-12-13 20:15:29 +00001641 /* Make description vector. */
1642 for (i = 0; i < vector_max (cmd_vector); i++)
1643 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1644 {
hasso8c328f12004-10-05 21:01:23 +00001645 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001646 vector strvec = cmd_element->strvec;
1647
paul54aba542003-08-21 20:28:24 +00001648 /* if command is NULL, index may be equal to vector_max */
1649 if (command && index >= vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001650 vector_slot (cmd_vector, i) = NULL;
1651 else
1652 {
paul54aba542003-08-21 20:28:24 +00001653 /* Check if command is completed. */
1654 if (command == NULL && index == vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001655 {
1656 string = "<cr>";
1657 if (! desc_unique_string (matchvec, string))
1658 vector_set (matchvec, &desc_cr);
1659 }
1660 else
1661 {
hasso8c328f12004-10-05 21:01:23 +00001662 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001663 vector descvec = vector_slot (strvec, index);
1664 struct desc *desc;
1665
1666 for (j = 0; j < vector_max (descvec); j++)
1667 {
1668 desc = vector_slot (descvec, j);
paul54aba542003-08-21 20:28:24 +00001669 string = cmd_entry_function_desc (command, desc->cmd);
paul718e3742002-12-13 20:15:29 +00001670 if (string)
1671 {
1672 /* Uniqueness check */
1673 if (! desc_unique_string (matchvec, string))
1674 vector_set (matchvec, desc);
1675 }
1676 }
1677 }
1678 }
1679 }
1680 vector_free (cmd_vector);
1681
1682 if (vector_slot (matchvec, 0) == NULL)
1683 {
1684 vector_free (matchvec);
1685 *status= CMD_ERR_NO_MATCH;
1686 }
1687 else
1688 *status = CMD_SUCCESS;
1689
1690 return matchvec;
1691}
1692
paulb92938a2002-12-13 21:20:42 +00001693vector
1694cmd_describe_command (vector vline, struct vty *vty, int *status)
1695{
1696 vector ret;
1697
1698 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1699 {
1700 enum node_type onode;
1701 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001702 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001703
1704 onode = vty->node;
1705 vty->node = ENABLE_NODE;
1706 /* We can try it on enable node, cos' the vty is authenticated */
1707
1708 shifted_vline = vector_init (vector_count(vline));
1709 /* use memcpy? */
1710 for (index = 1; index < vector_max (vline); index++)
1711 {
1712 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1713 }
1714
1715 ret = cmd_describe_command_real (shifted_vline, vty, status);
1716
1717 vector_free(shifted_vline);
1718 vty->node = onode;
1719 return ret;
1720 }
1721
1722
1723 return cmd_describe_command_real (vline, vty, status);
1724}
1725
1726
paul718e3742002-12-13 20:15:29 +00001727/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001728static int
paul718e3742002-12-13 20:15:29 +00001729cmd_lcd (char **matched)
1730{
1731 int i;
1732 int j;
1733 int lcd = -1;
1734 char *s1, *s2;
1735 char c1, c2;
1736
1737 if (matched[0] == NULL || matched[1] == NULL)
1738 return 0;
1739
1740 for (i = 1; matched[i] != NULL; i++)
1741 {
1742 s1 = matched[i - 1];
1743 s2 = matched[i];
1744
1745 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1746 if (c1 != c2)
1747 break;
1748
1749 if (lcd < 0)
1750 lcd = j;
1751 else
1752 {
1753 if (lcd > j)
1754 lcd = j;
1755 }
1756 }
1757 return lcd;
1758}
1759
1760/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001761static char **
paulb92938a2002-12-13 21:20:42 +00001762cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001763{
hasso8c328f12004-10-05 21:01:23 +00001764 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001765 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1766#define INIT_MATCHVEC_SIZE 10
1767 vector matchvec;
1768 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001769 unsigned int index = vector_max (vline) - 1;
paul718e3742002-12-13 20:15:29 +00001770 char **match_str;
1771 struct desc *desc;
1772 vector descvec;
1773 char *command;
1774 int lcd;
1775
1776 /* First, filter by preceeding command string */
1777 for (i = 0; i < index; i++)
1778 {
1779 enum match_type match;
1780 int ret;
1781
1782 command = vector_slot (vline, i);
1783
1784 /* First try completion match, if there is exactly match return 1 */
1785 match = cmd_filter_by_completion (command, cmd_vector, i);
1786
1787 /* If there is exact match then filter ambiguous match else check
1788 ambiguousness. */
1789 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1790 {
1791 vector_free (cmd_vector);
1792 *status = CMD_ERR_AMBIGUOUS;
1793 return NULL;
1794 }
1795 /*
1796 else if (ret == 2)
1797 {
1798 vector_free (cmd_vector);
1799 *status = CMD_ERR_NO_MATCH;
1800 return NULL;
1801 }
1802 */
1803 }
1804
1805 /* Prepare match vector. */
1806 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1807
1808 /* Now we got into completion */
1809 for (i = 0; i < vector_max (cmd_vector); i++)
1810 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1811 {
hasso8c328f12004-10-05 21:01:23 +00001812 const char *string;
paul718e3742002-12-13 20:15:29 +00001813 vector strvec = cmd_element->strvec;
1814
1815 /* Check field length */
1816 if (index >= vector_max (strvec))
1817 vector_slot (cmd_vector, i) = NULL;
1818 else
1819 {
hasso8c328f12004-10-05 21:01:23 +00001820 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001821
1822 descvec = vector_slot (strvec, index);
1823 for (j = 0; j < vector_max (descvec); j++)
1824 {
1825 desc = vector_slot (descvec, j);
1826
1827 if ((string = cmd_entry_function (vector_slot (vline, index),
1828 desc->cmd)))
1829 if (cmd_unique_string (matchvec, string))
1830 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1831 }
1832 }
1833 }
1834
1835 /* We don't need cmd_vector any more. */
1836 vector_free (cmd_vector);
1837
1838 /* No matched command */
1839 if (vector_slot (matchvec, 0) == NULL)
1840 {
1841 vector_free (matchvec);
1842
1843 /* In case of 'command \t' pattern. Do you need '?' command at
1844 the end of the line. */
1845 if (vector_slot (vline, index) == '\0')
1846 *status = CMD_ERR_NOTHING_TODO;
1847 else
1848 *status = CMD_ERR_NO_MATCH;
1849 return NULL;
1850 }
1851
1852 /* Only one matched */
1853 if (vector_slot (matchvec, 1) == NULL)
1854 {
1855 match_str = (char **) matchvec->index;
1856 vector_only_wrapper_free (matchvec);
1857 *status = CMD_COMPLETE_FULL_MATCH;
1858 return match_str;
1859 }
1860 /* Make it sure last element is NULL. */
1861 vector_set (matchvec, NULL);
1862
1863 /* Check LCD of matched strings. */
1864 if (vector_slot (vline, index) != NULL)
1865 {
1866 lcd = cmd_lcd ((char **) matchvec->index);
1867
1868 if (lcd)
1869 {
1870 int len = strlen (vector_slot (vline, index));
1871
1872 if (len < lcd)
1873 {
1874 char *lcdstr;
1875
1876 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1877 memcpy (lcdstr, matchvec->index[0], lcd);
1878 lcdstr[lcd] = '\0';
1879
1880 /* match_str = (char **) &lcdstr; */
1881
1882 /* Free matchvec. */
1883 for (i = 0; i < vector_max (matchvec); i++)
1884 {
1885 if (vector_slot (matchvec, i))
1886 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1887 }
1888 vector_free (matchvec);
1889
1890 /* Make new matchvec. */
1891 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1892 vector_set (matchvec, lcdstr);
1893 match_str = (char **) matchvec->index;
1894 vector_only_wrapper_free (matchvec);
1895
1896 *status = CMD_COMPLETE_MATCH;
1897 return match_str;
1898 }
1899 }
1900 }
1901
1902 match_str = (char **) matchvec->index;
1903 vector_only_wrapper_free (matchvec);
1904 *status = CMD_COMPLETE_LIST_MATCH;
1905 return match_str;
1906}
1907
paulb92938a2002-12-13 21:20:42 +00001908char **
paul9ab68122003-01-18 01:16:20 +00001909cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001910{
1911 char **ret;
1912
1913 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1914 {
1915 enum node_type onode;
1916 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001917 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001918
1919 onode = vty->node;
1920 vty->node = ENABLE_NODE;
1921 /* We can try it on enable node, cos' the vty is authenticated */
1922
1923 shifted_vline = vector_init (vector_count(vline));
1924 /* use memcpy? */
1925 for (index = 1; index < vector_max (vline); index++)
1926 {
1927 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1928 }
1929
1930 ret = cmd_complete_command_real (shifted_vline, vty, status);
1931
1932 vector_free(shifted_vline);
1933 vty->node = onode;
1934 return ret;
1935 }
1936
1937
1938 return cmd_complete_command_real (vline, vty, status);
1939}
1940
1941/* return parent node */
1942/* MUST eventually converge on CONFIG_NODE */
ajs274a4a42004-12-07 15:39:31 +00001943static enum node_type
1944node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001945{
1946 enum node_type ret;
1947
paul9ab68122003-01-18 01:16:20 +00001948 assert (node > CONFIG_NODE);
1949
1950 switch (node)
1951 {
1952 case BGP_VPNV4_NODE:
1953 case BGP_IPV4_NODE:
1954 case BGP_IPV4M_NODE:
1955 case BGP_IPV6_NODE:
1956 ret = BGP_NODE;
1957 break;
1958 case KEYCHAIN_KEY_NODE:
1959 ret = KEYCHAIN_NODE;
1960 break;
1961 default:
1962 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001963 }
1964
1965 return ret;
1966}
1967
paul718e3742002-12-13 20:15:29 +00001968/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001969static int
paulb92938a2002-12-13 21:20:42 +00001970cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001971{
hasso8c328f12004-10-05 21:01:23 +00001972 unsigned int i;
1973 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001974 vector cmd_vector;
1975 struct cmd_element *cmd_element;
1976 struct cmd_element *matched_element;
1977 unsigned int matched_count, incomplete_count;
1978 int argc;
paul9035efa2004-10-10 11:56:56 +00001979 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001980 enum match_type match = 0;
1981 int varflag;
1982 char *command;
1983
1984 /* Make copy of command elements. */
1985 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1986
1987 for (index = 0; index < vector_max (vline); index++)
1988 {
1989 int ret;
1990
1991 command = vector_slot (vline, index);
1992
1993 match = cmd_filter_by_completion (command, cmd_vector, index);
1994
1995 if (match == vararg_match)
1996 break;
1997
1998 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1999
2000 if (ret == 1)
2001 {
2002 vector_free (cmd_vector);
2003 return CMD_ERR_AMBIGUOUS;
2004 }
2005 else if (ret == 2)
2006 {
2007 vector_free (cmd_vector);
2008 return CMD_ERR_NO_MATCH;
2009 }
2010 }
2011
2012 /* Check matched count. */
2013 matched_element = NULL;
2014 matched_count = 0;
2015 incomplete_count = 0;
2016
2017 for (i = 0; i < vector_max (cmd_vector); i++)
2018 if (vector_slot (cmd_vector,i) != NULL)
2019 {
2020 cmd_element = vector_slot (cmd_vector,i);
2021
2022 if (match == vararg_match || index >= cmd_element->cmdsize)
2023 {
2024 matched_element = cmd_element;
2025#if 0
2026 printf ("DEBUG: %s\n", cmd_element->string);
2027#endif
2028 matched_count++;
2029 }
2030 else
2031 {
2032 incomplete_count++;
2033 }
2034 }
2035
2036 /* Finish of using cmd_vector. */
2037 vector_free (cmd_vector);
2038
2039 /* To execute command, matched_count must be 1.*/
2040 if (matched_count == 0)
2041 {
2042 if (incomplete_count)
2043 return CMD_ERR_INCOMPLETE;
2044 else
2045 return CMD_ERR_NO_MATCH;
2046 }
2047
2048 if (matched_count > 1)
2049 return CMD_ERR_AMBIGUOUS;
2050
2051 /* Argument treatment */
2052 varflag = 0;
2053 argc = 0;
2054
2055 for (i = 0; i < vector_max (vline); i++)
2056 {
2057 if (varflag)
2058 argv[argc++] = vector_slot (vline, i);
2059 else
2060 {
2061 vector descvec = vector_slot (matched_element->strvec, i);
2062
2063 if (vector_max (descvec) == 1)
2064 {
2065 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002066
hasso8c328f12004-10-05 21:01:23 +00002067 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002068 varflag = 1;
2069
hasso8c328f12004-10-05 21:01:23 +00002070 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002071 argv[argc++] = vector_slot (vline, i);
2072 }
2073 else
2074 argv[argc++] = vector_slot (vline, i);
2075 }
2076
2077 if (argc >= CMD_ARGC_MAX)
2078 return CMD_ERR_EXEED_ARGC_MAX;
2079 }
2080
2081 /* For vtysh execution. */
2082 if (cmd)
2083 *cmd = matched_element;
2084
2085 if (matched_element->daemon)
2086 return CMD_SUCCESS_DAEMON;
2087
2088 /* Execute matched command. */
2089 return (*matched_element->func) (matched_element, vty, argc, argv);
2090}
2091
paulb92938a2002-12-13 21:20:42 +00002092
2093int
2094cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd) {
paul9ab68122003-01-18 01:16:20 +00002095 int ret, saved_ret, tried = 0;
2096 enum node_type onode, try_node;
2097
2098 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002099
2100 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2101 {
2102 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002103 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002104
2105 vty->node = ENABLE_NODE;
2106 /* We can try it on enable node, cos' the vty is authenticated */
2107
2108 shifted_vline = vector_init (vector_count(vline));
2109 /* use memcpy? */
2110 for (index = 1; index < vector_max (vline); index++)
2111 {
2112 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2113 }
2114
2115 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2116
2117 vector_free(shifted_vline);
2118 vty->node = onode;
2119 return ret;
2120 }
2121
2122
paul9ab68122003-01-18 01:16:20 +00002123 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002124
2125 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002126 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002127 && vty->node > CONFIG_NODE )
2128 {
paul9ab68122003-01-18 01:16:20 +00002129 try_node = node_parent(try_node);
2130 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002131 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002132 tried = 1;
2133 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002134 {
paul9ab68122003-01-18 01:16:20 +00002135 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002136 return ret;
2137 }
paulb92938a2002-12-13 21:20:42 +00002138 }
paul9ab68122003-01-18 01:16:20 +00002139 /* no command succeeded, reset the vty to the original node and
2140 return the error for this node */
2141 if ( tried )
2142 vty->node = onode;
2143 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002144}
2145
paul718e3742002-12-13 20:15:29 +00002146/* Execute command by argument readline. */
2147int
2148cmd_execute_command_strict (vector vline, struct vty *vty,
2149 struct cmd_element **cmd)
2150{
hasso8c328f12004-10-05 21:01:23 +00002151 unsigned int i;
2152 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002153 vector cmd_vector;
2154 struct cmd_element *cmd_element;
2155 struct cmd_element *matched_element;
2156 unsigned int matched_count, incomplete_count;
2157 int argc;
paul9035efa2004-10-10 11:56:56 +00002158 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002159 int varflag;
2160 enum match_type match = 0;
2161 char *command;
2162
2163 /* Make copy of command element */
2164 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2165
2166 for (index = 0; index < vector_max (vline); index++)
2167 {
2168 int ret;
2169
2170 command = vector_slot (vline, index);
2171
2172 match = cmd_filter_by_string (vector_slot (vline, index),
2173 cmd_vector, index);
2174
2175 /* If command meets '.VARARG' then finish matching. */
2176 if (match == vararg_match)
2177 break;
2178
2179 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2180 if (ret == 1)
2181 {
2182 vector_free (cmd_vector);
2183 return CMD_ERR_AMBIGUOUS;
2184 }
2185 if (ret == 2)
2186 {
2187 vector_free (cmd_vector);
2188 return CMD_ERR_NO_MATCH;
2189 }
2190 }
2191
2192 /* Check matched count. */
2193 matched_element = NULL;
2194 matched_count = 0;
2195 incomplete_count = 0;
2196 for (i = 0; i < vector_max (cmd_vector); i++)
2197 if (vector_slot (cmd_vector,i) != NULL)
2198 {
2199 cmd_element = vector_slot (cmd_vector,i);
2200
2201 if (match == vararg_match || index >= cmd_element->cmdsize)
2202 {
2203 matched_element = cmd_element;
2204 matched_count++;
2205 }
2206 else
2207 incomplete_count++;
2208 }
2209
2210 /* Finish of using cmd_vector. */
2211 vector_free (cmd_vector);
2212
2213 /* To execute command, matched_count must be 1.*/
2214 if (matched_count == 0)
2215 {
2216 if (incomplete_count)
2217 return CMD_ERR_INCOMPLETE;
2218 else
2219 return CMD_ERR_NO_MATCH;
2220 }
2221
2222 if (matched_count > 1)
2223 return CMD_ERR_AMBIGUOUS;
2224
2225 /* Argument treatment */
2226 varflag = 0;
2227 argc = 0;
2228
2229 for (i = 0; i < vector_max (vline); i++)
2230 {
2231 if (varflag)
2232 argv[argc++] = vector_slot (vline, i);
2233 else
2234 {
2235 vector descvec = vector_slot (matched_element->strvec, i);
2236
2237 if (vector_max (descvec) == 1)
2238 {
2239 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002240
hasso8c328f12004-10-05 21:01:23 +00002241 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002242 varflag = 1;
2243
hasso8c328f12004-10-05 21:01:23 +00002244 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002245 argv[argc++] = vector_slot (vline, i);
2246 }
2247 else
2248 argv[argc++] = vector_slot (vline, i);
2249 }
2250
2251 if (argc >= CMD_ARGC_MAX)
2252 return CMD_ERR_EXEED_ARGC_MAX;
2253 }
2254
2255 /* For vtysh execution. */
2256 if (cmd)
2257 *cmd = matched_element;
2258
2259 if (matched_element->daemon)
2260 return CMD_SUCCESS_DAEMON;
2261
2262 /* Now execute matched command */
2263 return (*matched_element->func) (matched_element, vty, argc, argv);
2264}
2265
2266/* Configration make from file. */
2267int
2268config_from_file (struct vty *vty, FILE *fp)
2269{
2270 int ret;
2271 vector vline;
2272
2273 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2274 {
2275 vline = cmd_make_strvec (vty->buf);
2276
2277 /* In case of comment line */
2278 if (vline == NULL)
2279 continue;
2280 /* Execute configuration command : this is strict match */
2281 ret = cmd_execute_command_strict (vline, vty, NULL);
2282
2283 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002284 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002285 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2286 {
paulb92938a2002-12-13 21:20:42 +00002287 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002288 ret = cmd_execute_command_strict (vline, vty, NULL);
2289 }
paul9ab68122003-01-18 01:16:20 +00002290
paul718e3742002-12-13 20:15:29 +00002291 cmd_free_strvec (vline);
2292
hassoddd85ed2004-10-13 08:18:07 +00002293 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2294 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002295 return ret;
2296 }
2297 return CMD_SUCCESS;
2298}
2299
2300/* Configration from terminal */
2301DEFUN (config_terminal,
2302 config_terminal_cmd,
2303 "configure terminal",
2304 "Configuration from vty interface\n"
2305 "Configuration terminal\n")
2306{
2307 if (vty_config_lock (vty))
2308 vty->node = CONFIG_NODE;
2309 else
2310 {
2311 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2312 return CMD_WARNING;
2313 }
2314 return CMD_SUCCESS;
2315}
2316
2317/* Enable command */
2318DEFUN (enable,
2319 config_enable_cmd,
2320 "enable",
2321 "Turn on privileged mode command\n")
2322{
2323 /* If enable password is NULL, change to ENABLE_NODE */
2324 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2325 vty->type == VTY_SHELL_SERV)
2326 vty->node = ENABLE_NODE;
2327 else
2328 vty->node = AUTH_ENABLE_NODE;
2329
2330 return CMD_SUCCESS;
2331}
2332
2333/* Disable command */
2334DEFUN (disable,
2335 config_disable_cmd,
2336 "disable",
2337 "Turn off privileged mode command\n")
2338{
2339 if (vty->node == ENABLE_NODE)
2340 vty->node = VIEW_NODE;
2341 return CMD_SUCCESS;
2342}
2343
2344/* Down vty node level. */
2345DEFUN (config_exit,
2346 config_exit_cmd,
2347 "exit",
2348 "Exit current mode and down to previous mode\n")
2349{
2350 switch (vty->node)
2351 {
2352 case VIEW_NODE:
2353 case ENABLE_NODE:
2354 if (vty_shell (vty))
2355 exit (0);
2356 else
2357 vty->status = VTY_CLOSE;
2358 break;
2359 case CONFIG_NODE:
2360 vty->node = ENABLE_NODE;
2361 vty_config_unlock (vty);
2362 break;
2363 case INTERFACE_NODE:
2364 case ZEBRA_NODE:
2365 case BGP_NODE:
2366 case RIP_NODE:
2367 case RIPNG_NODE:
2368 case OSPF_NODE:
2369 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002370 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002371 case KEYCHAIN_NODE:
2372 case MASC_NODE:
2373 case RMAP_NODE:
2374 case VTY_NODE:
2375 vty->node = CONFIG_NODE;
2376 break;
2377 case BGP_VPNV4_NODE:
2378 case BGP_IPV4_NODE:
2379 case BGP_IPV4M_NODE:
2380 case BGP_IPV6_NODE:
2381 vty->node = BGP_NODE;
2382 break;
2383 case KEYCHAIN_KEY_NODE:
2384 vty->node = KEYCHAIN_NODE;
2385 break;
2386 default:
2387 break;
2388 }
2389 return CMD_SUCCESS;
2390}
2391
2392/* quit is alias of exit. */
2393ALIAS (config_exit,
2394 config_quit_cmd,
2395 "quit",
2396 "Exit current mode and down to previous mode\n")
2397
2398/* End of configuration. */
2399DEFUN (config_end,
2400 config_end_cmd,
2401 "end",
2402 "End current mode and change to enable mode.")
2403{
2404 switch (vty->node)
2405 {
2406 case VIEW_NODE:
2407 case ENABLE_NODE:
2408 /* Nothing to do. */
2409 break;
2410 case CONFIG_NODE:
2411 case INTERFACE_NODE:
2412 case ZEBRA_NODE:
2413 case RIP_NODE:
2414 case RIPNG_NODE:
2415 case BGP_NODE:
2416 case BGP_VPNV4_NODE:
2417 case BGP_IPV4_NODE:
2418 case BGP_IPV4M_NODE:
2419 case BGP_IPV6_NODE:
2420 case RMAP_NODE:
2421 case OSPF_NODE:
2422 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002423 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002424 case KEYCHAIN_NODE:
2425 case KEYCHAIN_KEY_NODE:
2426 case MASC_NODE:
2427 case VTY_NODE:
2428 vty_config_unlock (vty);
2429 vty->node = ENABLE_NODE;
2430 break;
2431 default:
2432 break;
2433 }
2434 return CMD_SUCCESS;
2435}
2436
2437/* Show version. */
2438DEFUN (show_version,
2439 show_version_cmd,
2440 "show version",
2441 SHOW_STR
2442 "Displays zebra version\n")
2443{
hasso6590f2c2004-10-19 20:40:08 +00002444 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name, VTY_NEWLINE);
2445 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002446
2447 return CMD_SUCCESS;
2448}
2449
2450/* Help display function for all node. */
2451DEFUN (config_help,
2452 config_help_cmd,
2453 "help",
2454 "Description of the interactive help system\n")
2455{
2456 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002457 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002458anytime at the command line please press '?'.%s\
2459%s\
2460If nothing matches, the help list will be empty and you must backup%s\
2461 until entering a '?' shows the available options.%s\
2462Two styles of help are provided:%s\
24631. Full help is available when you are ready to enter a%s\
2464command argument (e.g. 'show ?') and describes each possible%s\
2465argument.%s\
24662. Partial help is provided when an abbreviated argument is entered%s\
2467 and you want to know what arguments match the input%s\
2468 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2469 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2470 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2471 return CMD_SUCCESS;
2472}
2473
2474/* Help display function for all node. */
2475DEFUN (config_list,
2476 config_list_cmd,
2477 "list",
2478 "Print command list\n")
2479{
hasso8c328f12004-10-05 21:01:23 +00002480 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002481 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2482 struct cmd_element *cmd;
2483
2484 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2485 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2486 vty_out (vty, " %s%s", cmd->string,
2487 VTY_NEWLINE);
2488 return CMD_SUCCESS;
2489}
2490
2491/* Write current configuration into file. */
2492DEFUN (config_write_file,
2493 config_write_file_cmd,
2494 "write file",
2495 "Write running configuration to memory, network, or terminal\n"
2496 "Write to configuration file\n")
2497{
hasso8c328f12004-10-05 21:01:23 +00002498 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002499 int fd;
2500 struct cmd_node *node;
2501 char *config_file;
2502 char *config_file_tmp = NULL;
2503 char *config_file_sav = NULL;
2504 struct vty *file_vty;
2505
2506 /* Check and see if we are operating under vtysh configuration */
2507 if (host.config == NULL)
2508 {
2509 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2510 VTY_NEWLINE);
2511 return CMD_WARNING;
2512 }
2513
2514 /* Get filename. */
2515 config_file = host.config;
2516
2517 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2518 strcpy (config_file_sav, config_file);
2519 strcat (config_file_sav, CONF_BACKUP_EXT);
2520
2521
2522 config_file_tmp = malloc (strlen (config_file) + 8);
2523 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2524
2525 /* Open file to configuration write. */
2526 fd = mkstemp (config_file_tmp);
2527 if (fd < 0)
2528 {
2529 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2530 VTY_NEWLINE);
2531 free (config_file_tmp);
2532 free (config_file_sav);
2533 return CMD_WARNING;
2534 }
2535
2536 /* Make vty for configuration file. */
2537 file_vty = vty_new ();
2538 file_vty->fd = fd;
2539 file_vty->type = VTY_FILE;
2540
2541 /* Config file header print. */
2542 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2543 vty_time_print (file_vty, 1);
2544 vty_out (file_vty, "!\n");
2545
2546 for (i = 0; i < vector_max (cmdvec); i++)
2547 if ((node = vector_slot (cmdvec, i)) && node->func)
2548 {
2549 if ((*node->func) (file_vty))
2550 vty_out (file_vty, "!\n");
2551 }
2552 vty_close (file_vty);
2553
2554 if (unlink (config_file_sav) != 0)
2555 if (errno != ENOENT)
2556 {
2557 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2558 VTY_NEWLINE);
2559 free (config_file_sav);
2560 free (config_file_tmp);
2561 unlink (config_file_tmp);
2562 return CMD_WARNING;
2563 }
2564 if (link (config_file, config_file_sav) != 0)
2565 {
2566 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2567 VTY_NEWLINE);
2568 free (config_file_sav);
2569 free (config_file_tmp);
2570 unlink (config_file_tmp);
2571 return CMD_WARNING;
2572 }
2573 sync ();
2574 if (unlink (config_file) != 0)
2575 {
2576 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2577 VTY_NEWLINE);
2578 free (config_file_sav);
2579 free (config_file_tmp);
2580 unlink (config_file_tmp);
2581 return CMD_WARNING;
2582 }
2583 if (link (config_file_tmp, config_file) != 0)
2584 {
2585 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2586 VTY_NEWLINE);
2587 free (config_file_sav);
2588 free (config_file_tmp);
2589 unlink (config_file_tmp);
2590 return CMD_WARNING;
2591 }
2592 unlink (config_file_tmp);
2593 sync ();
2594
2595 free (config_file_sav);
2596 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002597
2598 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2599 {
2600 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002601 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002602 return CMD_WARNING;
2603 }
2604
paul718e3742002-12-13 20:15:29 +00002605 vty_out (vty, "Configuration saved to %s%s", config_file,
2606 VTY_NEWLINE);
2607 return CMD_SUCCESS;
2608}
2609
2610ALIAS (config_write_file,
2611 config_write_cmd,
2612 "write",
2613 "Write running configuration to memory, network, or terminal\n")
2614
2615ALIAS (config_write_file,
2616 config_write_memory_cmd,
2617 "write memory",
2618 "Write running configuration to memory, network, or terminal\n"
2619 "Write configuration to the file (same as write file)\n")
2620
2621ALIAS (config_write_file,
2622 copy_runningconfig_startupconfig_cmd,
2623 "copy running-config startup-config",
2624 "Copy configuration\n"
2625 "Copy running config to... \n"
2626 "Copy running config to startup config (same as write file)\n")
2627
2628/* Write current configuration into the terminal. */
2629DEFUN (config_write_terminal,
2630 config_write_terminal_cmd,
2631 "write terminal",
2632 "Write running configuration to memory, network, or terminal\n"
2633 "Write to terminal\n")
2634{
hasso8c328f12004-10-05 21:01:23 +00002635 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002636 struct cmd_node *node;
2637
2638 if (vty->type == VTY_SHELL_SERV)
2639 {
2640 for (i = 0; i < vector_max (cmdvec); i++)
2641 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2642 {
2643 if ((*node->func) (vty))
2644 vty_out (vty, "!%s", VTY_NEWLINE);
2645 }
2646 }
2647 else
2648 {
2649 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2650 VTY_NEWLINE);
2651 vty_out (vty, "!%s", VTY_NEWLINE);
2652
2653 for (i = 0; i < vector_max (cmdvec); i++)
2654 if ((node = vector_slot (cmdvec, i)) && node->func)
2655 {
2656 if ((*node->func) (vty))
2657 vty_out (vty, "!%s", VTY_NEWLINE);
2658 }
2659 vty_out (vty, "end%s",VTY_NEWLINE);
2660 }
2661 return CMD_SUCCESS;
2662}
2663
2664/* Write current configuration into the terminal. */
2665ALIAS (config_write_terminal,
2666 show_running_config_cmd,
2667 "show running-config",
2668 SHOW_STR
2669 "running configuration\n")
2670
2671/* Write startup configuration into the terminal. */
2672DEFUN (show_startup_config,
2673 show_startup_config_cmd,
2674 "show startup-config",
2675 SHOW_STR
2676 "Contentes of startup configuration\n")
2677{
2678 char buf[BUFSIZ];
2679 FILE *confp;
2680
2681 confp = fopen (host.config, "r");
2682 if (confp == NULL)
2683 {
2684 vty_out (vty, "Can't open configuration file [%s]%s",
2685 host.config, VTY_NEWLINE);
2686 return CMD_WARNING;
2687 }
2688
2689 while (fgets (buf, BUFSIZ, confp))
2690 {
2691 char *cp = buf;
2692
2693 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2694 cp++;
2695 *cp = '\0';
2696
2697 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2698 }
2699
2700 fclose (confp);
2701
2702 return CMD_SUCCESS;
2703}
2704
2705/* Hostname configuration */
2706DEFUN (config_hostname,
2707 hostname_cmd,
2708 "hostname WORD",
2709 "Set system's network name\n"
2710 "This system's network name\n")
2711{
2712 if (!isalpha((int) *argv[0]))
2713 {
2714 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2715 return CMD_WARNING;
2716 }
2717
2718 if (host.name)
2719 XFREE (0, host.name);
2720
2721 host.name = strdup (argv[0]);
2722 return CMD_SUCCESS;
2723}
2724
2725DEFUN (config_no_hostname,
2726 no_hostname_cmd,
2727 "no hostname [HOSTNAME]",
2728 NO_STR
2729 "Reset system's network name\n"
2730 "Host name of this router\n")
2731{
2732 if (host.name)
2733 XFREE (0, host.name);
2734 host.name = NULL;
2735 return CMD_SUCCESS;
2736}
2737
2738/* VTY interface password set. */
2739DEFUN (config_password, password_cmd,
2740 "password (8|) WORD",
2741 "Assign the terminal connection password\n"
2742 "Specifies a HIDDEN password will follow\n"
2743 "dummy string \n"
2744 "The HIDDEN line password string\n")
2745{
2746 /* Argument check. */
2747 if (argc == 0)
2748 {
2749 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2750 return CMD_WARNING;
2751 }
2752
2753 if (argc == 2)
2754 {
2755 if (*argv[0] == '8')
2756 {
2757 if (host.password)
2758 XFREE (0, host.password);
2759 host.password = NULL;
2760 if (host.password_encrypt)
2761 XFREE (0, host.password_encrypt);
2762 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2763 return CMD_SUCCESS;
2764 }
2765 else
2766 {
2767 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2768 return CMD_WARNING;
2769 }
2770 }
2771
2772 if (!isalnum ((int) *argv[0]))
2773 {
2774 vty_out (vty,
2775 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2776 return CMD_WARNING;
2777 }
2778
2779 if (host.password)
2780 XFREE (0, host.password);
2781 host.password = NULL;
2782
2783 if (host.encrypt)
2784 {
2785 if (host.password_encrypt)
2786 XFREE (0, host.password_encrypt);
2787 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2788 }
2789 else
2790 host.password = XSTRDUP (0, argv[0]);
2791
2792 return CMD_SUCCESS;
2793}
2794
2795ALIAS (config_password, password_text_cmd,
2796 "password LINE",
2797 "Assign the terminal connection password\n"
2798 "The UNENCRYPTED (cleartext) line password\n")
2799
2800/* VTY enable password set. */
2801DEFUN (config_enable_password, enable_password_cmd,
2802 "enable password (8|) WORD",
2803 "Modify enable password parameters\n"
2804 "Assign the privileged level password\n"
2805 "Specifies a HIDDEN password will follow\n"
2806 "dummy string \n"
2807 "The HIDDEN 'enable' password string\n")
2808{
2809 /* Argument check. */
2810 if (argc == 0)
2811 {
2812 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2813 return CMD_WARNING;
2814 }
2815
2816 /* Crypt type is specified. */
2817 if (argc == 2)
2818 {
2819 if (*argv[0] == '8')
2820 {
2821 if (host.enable)
2822 XFREE (0, host.enable);
2823 host.enable = NULL;
2824
2825 if (host.enable_encrypt)
2826 XFREE (0, host.enable_encrypt);
2827 host.enable_encrypt = XSTRDUP (0, argv[1]);
2828
2829 return CMD_SUCCESS;
2830 }
2831 else
2832 {
2833 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2834 return CMD_WARNING;
2835 }
2836 }
2837
2838 if (!isalnum ((int) *argv[0]))
2839 {
2840 vty_out (vty,
2841 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2842 return CMD_WARNING;
2843 }
2844
2845 if (host.enable)
2846 XFREE (0, host.enable);
2847 host.enable = NULL;
2848
2849 /* Plain password input. */
2850 if (host.encrypt)
2851 {
2852 if (host.enable_encrypt)
2853 XFREE (0, host.enable_encrypt);
2854 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2855 }
2856 else
2857 host.enable = XSTRDUP (0, argv[0]);
2858
2859 return CMD_SUCCESS;
2860}
2861
2862ALIAS (config_enable_password,
2863 enable_password_text_cmd,
2864 "enable password LINE",
2865 "Modify enable password parameters\n"
2866 "Assign the privileged level password\n"
2867 "The UNENCRYPTED (cleartext) 'enable' password\n")
2868
2869/* VTY enable password delete. */
2870DEFUN (no_config_enable_password, no_enable_password_cmd,
2871 "no enable password",
2872 NO_STR
2873 "Modify enable password parameters\n"
2874 "Assign the privileged level password\n")
2875{
2876 if (host.enable)
2877 XFREE (0, host.enable);
2878 host.enable = NULL;
2879
2880 if (host.enable_encrypt)
2881 XFREE (0, host.enable_encrypt);
2882 host.enable_encrypt = NULL;
2883
2884 return CMD_SUCCESS;
2885}
2886
2887DEFUN (service_password_encrypt,
2888 service_password_encrypt_cmd,
2889 "service password-encryption",
2890 "Set up miscellaneous service\n"
2891 "Enable encrypted passwords\n")
2892{
2893 if (host.encrypt)
2894 return CMD_SUCCESS;
2895
2896 host.encrypt = 1;
2897
2898 if (host.password)
2899 {
2900 if (host.password_encrypt)
2901 XFREE (0, host.password_encrypt);
2902 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2903 }
2904 if (host.enable)
2905 {
2906 if (host.enable_encrypt)
2907 XFREE (0, host.enable_encrypt);
2908 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2909 }
2910
2911 return CMD_SUCCESS;
2912}
2913
2914DEFUN (no_service_password_encrypt,
2915 no_service_password_encrypt_cmd,
2916 "no service password-encryption",
2917 NO_STR
2918 "Set up miscellaneous service\n"
2919 "Enable encrypted passwords\n")
2920{
2921 if (! host.encrypt)
2922 return CMD_SUCCESS;
2923
2924 host.encrypt = 0;
2925
2926 if (host.password_encrypt)
2927 XFREE (0, host.password_encrypt);
2928 host.password_encrypt = NULL;
2929
2930 if (host.enable_encrypt)
2931 XFREE (0, host.enable_encrypt);
2932 host.enable_encrypt = NULL;
2933
2934 return CMD_SUCCESS;
2935}
2936
2937DEFUN (config_terminal_length, config_terminal_length_cmd,
2938 "terminal length <0-512>",
2939 "Set terminal line parameters\n"
2940 "Set number of lines on a screen\n"
2941 "Number of lines on screen (0 for no pausing)\n")
2942{
2943 int lines;
2944 char *endptr = NULL;
2945
2946 lines = strtol (argv[0], &endptr, 10);
2947 if (lines < 0 || lines > 512 || *endptr != '\0')
2948 {
2949 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2950 return CMD_WARNING;
2951 }
2952 vty->lines = lines;
2953
2954 return CMD_SUCCESS;
2955}
2956
2957DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2958 "terminal no length",
2959 "Set terminal line parameters\n"
2960 NO_STR
2961 "Set number of lines on a screen\n")
2962{
2963 vty->lines = -1;
2964 return CMD_SUCCESS;
2965}
2966
2967DEFUN (service_terminal_length, service_terminal_length_cmd,
2968 "service terminal-length <0-512>",
2969 "Set up miscellaneous service\n"
2970 "System wide terminal length configuration\n"
2971 "Number of lines of VTY (0 means no line control)\n")
2972{
2973 int lines;
2974 char *endptr = NULL;
2975
2976 lines = strtol (argv[0], &endptr, 10);
2977 if (lines < 0 || lines > 512 || *endptr != '\0')
2978 {
2979 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2980 return CMD_WARNING;
2981 }
2982 host.lines = lines;
2983
2984 return CMD_SUCCESS;
2985}
2986
2987DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2988 "no service terminal-length [<0-512>]",
2989 NO_STR
2990 "Set up miscellaneous service\n"
2991 "System wide terminal length configuration\n"
2992 "Number of lines of VTY (0 means no line control)\n")
2993{
2994 host.lines = -1;
2995 return CMD_SUCCESS;
2996}
2997
ajs2885f722004-12-17 23:16:33 +00002998DEFUN_HIDDEN (do_echo,
2999 echo_cmd,
3000 "echo .MESSAGE",
3001 "Echo a message back to the vty\n"
3002 "The message to echo\n")
3003{
3004 char *message;
3005
3006 vty_out (vty, "%s%s",(message = argv_concat(argv, argc, 0)), VTY_NEWLINE);
3007 XFREE(MTYPE_TMP, message);
3008 return CMD_SUCCESS;
3009}
3010
ajs274a4a42004-12-07 15:39:31 +00003011DEFUN (config_logmsg,
3012 config_logmsg_cmd,
3013 "logmsg "LOG_LEVELS" .MESSAGE",
3014 "Send a message to enabled logging destinations\n"
3015 LOG_LEVEL_DESC
3016 "The message to send\n")
3017{
3018 int level;
3019 char *message;
3020
3021 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3022 return CMD_ERR_NO_MATCH;
3023
3024 zlog(NULL, level, (message = argv_concat(argv, argc, 1)));
3025 XFREE(MTYPE_TMP, message);
3026 return CMD_SUCCESS;
3027}
3028
3029DEFUN (show_logging,
3030 show_logging_cmd,
3031 "show logging",
3032 SHOW_STR
3033 "Show current logging configuration\n")
3034{
3035 struct zlog *zl = zlog_default;
3036
3037 vty_out (vty, "Syslog logging: ");
3038 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3039 vty_out (vty, "disabled");
3040 else
3041 vty_out (vty, "level %s, facility %s, ident %s",
3042 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3043 facility_name(zl->facility), zl->ident);
3044 vty_out (vty, "%s", VTY_NEWLINE);
3045
3046 vty_out (vty, "Stdout logging: ");
3047 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3048 vty_out (vty, "disabled");
3049 else
3050 vty_out (vty, "level %s",
3051 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3052 vty_out (vty, "%s", VTY_NEWLINE);
3053
3054 vty_out (vty, "Monitor logging: ");
3055 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3056 vty_out (vty, "disabled");
3057 else
3058 vty_out (vty, "level %s",
3059 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3060 vty_out (vty, "%s", VTY_NEWLINE);
3061
3062 vty_out (vty, "File logging: ");
3063 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3064 !zl->fp)
3065 vty_out (vty, "disabled");
3066 else
3067 vty_out (vty, "level %s, filename %s",
3068 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3069 zl->filename);
3070 vty_out (vty, "%s", VTY_NEWLINE);
3071
3072 vty_out (vty, "Protocol name: %s%s",
3073 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3074 vty_out (vty, "Record priority: %s%s",
3075 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3076
3077 return CMD_SUCCESS;
3078}
3079
paul718e3742002-12-13 20:15:29 +00003080DEFUN (config_log_stdout,
3081 config_log_stdout_cmd,
3082 "log stdout",
3083 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003084 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003085{
ajs274a4a42004-12-07 15:39:31 +00003086 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3087 return CMD_SUCCESS;
3088}
3089
3090DEFUN (config_log_stdout_level,
3091 config_log_stdout_level_cmd,
3092 "log stdout "LOG_LEVELS,
3093 "Logging control\n"
3094 "Set stdout logging level\n"
3095 LOG_LEVEL_DESC)
3096{
3097 int level;
3098
3099 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3100 return CMD_ERR_NO_MATCH;
3101 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003102 return CMD_SUCCESS;
3103}
3104
3105DEFUN (no_config_log_stdout,
3106 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003107 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003108 NO_STR
3109 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003110 "Cancel logging to stdout\n"
3111 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003112{
ajs274a4a42004-12-07 15:39:31 +00003113 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003114 return CMD_SUCCESS;
3115}
3116
ajs274a4a42004-12-07 15:39:31 +00003117DEFUN (config_log_monitor,
3118 config_log_monitor_cmd,
3119 "log monitor",
paul718e3742002-12-13 20:15:29 +00003120 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003121 "Set terminal line (monitor) logging level\n")
3122{
3123 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3124 return CMD_SUCCESS;
3125}
3126
3127DEFUN (config_log_monitor_level,
3128 config_log_monitor_level_cmd,
3129 "log monitor "LOG_LEVELS,
3130 "Logging control\n"
3131 "Set terminal line (monitor) logging level\n"
3132 LOG_LEVEL_DESC)
3133{
3134 int level;
3135
3136 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3137 return CMD_ERR_NO_MATCH;
3138 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3139 return CMD_SUCCESS;
3140}
3141
3142DEFUN (no_config_log_monitor,
3143 no_config_log_monitor_cmd,
3144 "no log monitor [LEVEL]",
3145 NO_STR
3146 "Logging control\n"
3147 "Disable terminal line (monitor) logging\n"
3148 "Logging level\n")
3149{
3150 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3151 return CMD_SUCCESS;
3152}
3153
3154static int
3155set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003156{
3157 int ret;
paul9035efa2004-10-10 11:56:56 +00003158 char *p = NULL;
3159 const char *fullpath;
3160
paul718e3742002-12-13 20:15:29 +00003161 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003162 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003163 {
paul9035efa2004-10-10 11:56:56 +00003164 char cwd[MAXPATHLEN+1];
3165 cwd[MAXPATHLEN] = '\0';
3166
3167 if (getcwd (cwd, MAXPATHLEN) == NULL)
3168 {
3169 zlog_err ("config_log_file: Unable to alloc mem!");
3170 return CMD_WARNING;
3171 }
3172
ajs274a4a42004-12-07 15:39:31 +00003173 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003174 == NULL)
3175 {
3176 zlog_err ("config_log_file: Unable to alloc mem!");
3177 return CMD_WARNING;
3178 }
ajs274a4a42004-12-07 15:39:31 +00003179 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003180 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003181 }
3182 else
ajs274a4a42004-12-07 15:39:31 +00003183 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003184
ajs274a4a42004-12-07 15:39:31 +00003185 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003186
paul9035efa2004-10-10 11:56:56 +00003187 if (p)
3188 XFREE (MTYPE_TMP, p);
3189
paul718e3742002-12-13 20:15:29 +00003190 if (!ret)
3191 {
ajs274a4a42004-12-07 15:39:31 +00003192 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003193 return CMD_WARNING;
3194 }
3195
3196 if (host.logfile)
3197 XFREE (MTYPE_TMP, host.logfile);
3198
ajs274a4a42004-12-07 15:39:31 +00003199 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003200
3201 return CMD_SUCCESS;
3202}
3203
ajs274a4a42004-12-07 15:39:31 +00003204DEFUN (config_log_file,
3205 config_log_file_cmd,
3206 "log file FILENAME",
3207 "Logging control\n"
3208 "Logging to file\n"
3209 "Logging filename\n")
3210{
3211 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3212}
3213
3214DEFUN (config_log_file_level,
3215 config_log_file_level_cmd,
3216 "log file FILENAME "LOG_LEVELS,
3217 "Logging control\n"
3218 "Logging to file\n"
3219 "Logging filename\n"
3220 LOG_LEVEL_DESC)
3221{
3222 int level;
3223
3224 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3225 return CMD_ERR_NO_MATCH;
3226 return set_log_file(vty, argv[0], level);
3227}
3228
paul718e3742002-12-13 20:15:29 +00003229DEFUN (no_config_log_file,
3230 no_config_log_file_cmd,
3231 "no log file [FILENAME]",
3232 NO_STR
3233 "Logging control\n"
3234 "Cancel logging to file\n"
3235 "Logging file name\n")
3236{
3237 zlog_reset_file (NULL);
3238
3239 if (host.logfile)
3240 XFREE (MTYPE_TMP, host.logfile);
3241
3242 host.logfile = NULL;
3243
3244 return CMD_SUCCESS;
3245}
3246
ajs274a4a42004-12-07 15:39:31 +00003247ALIAS (no_config_log_file,
3248 no_config_log_file_level_cmd,
3249 "no log file FILENAME LEVEL",
3250 NO_STR
3251 "Logging control\n"
3252 "Cancel logging to file\n"
3253 "Logging file name\n"
3254 "Logging level\n")
3255
paul718e3742002-12-13 20:15:29 +00003256DEFUN (config_log_syslog,
3257 config_log_syslog_cmd,
3258 "log syslog",
3259 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003260 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003261{
ajs274a4a42004-12-07 15:39:31 +00003262 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003263 return CMD_SUCCESS;
3264}
3265
ajs274a4a42004-12-07 15:39:31 +00003266DEFUN (config_log_syslog_level,
3267 config_log_syslog_level_cmd,
3268 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003269 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003270 "Set syslog logging level\n"
3271 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003272{
ajs274a4a42004-12-07 15:39:31 +00003273 int level;
paul12ab19f2003-07-26 06:14:55 +00003274
ajs274a4a42004-12-07 15:39:31 +00003275 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3276 return CMD_ERR_NO_MATCH;
3277 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3278 return CMD_SUCCESS;
3279}
paul12ab19f2003-07-26 06:14:55 +00003280
ajs274a4a42004-12-07 15:39:31 +00003281DEFUN_DEPRECATED (config_log_syslog_facility,
3282 config_log_syslog_facility_cmd,
3283 "log syslog facility "LOG_FACILITIES,
3284 "Logging control\n"
3285 "Logging goes to syslog\n"
3286 "(Deprecated) Facility parameter for syslog messages\n"
3287 LOG_FACILITY_DESC)
3288{
3289 int facility;
paul12ab19f2003-07-26 06:14:55 +00003290
ajs274a4a42004-12-07 15:39:31 +00003291 if ((facility = facility_match(argv[0])) < 0)
3292 return CMD_ERR_NO_MATCH;
3293
3294 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003295 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003296 return CMD_SUCCESS;
3297}
3298
3299DEFUN (no_config_log_syslog,
3300 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003301 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003302 NO_STR
3303 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003304 "Cancel logging to syslog\n"
3305 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003306{
ajs274a4a42004-12-07 15:39:31 +00003307 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003308 return CMD_SUCCESS;
3309}
3310
paul12ab19f2003-07-26 06:14:55 +00003311ALIAS (no_config_log_syslog,
3312 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003313 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003314 NO_STR
3315 "Logging control\n"
3316 "Logging goes to syslog\n"
3317 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003318 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003319
ajs274a4a42004-12-07 15:39:31 +00003320DEFUN (config_log_facility,
3321 config_log_facility_cmd,
3322 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003323 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003324 "Facility parameter for syslog messages\n"
3325 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003326{
ajs274a4a42004-12-07 15:39:31 +00003327 int facility;
3328
3329 if ((facility = facility_match(argv[0])) < 0)
3330 return CMD_ERR_NO_MATCH;
3331 zlog_default->facility = facility;
3332 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003333}
3334
ajs274a4a42004-12-07 15:39:31 +00003335DEFUN (no_config_log_facility,
3336 no_config_log_facility_cmd,
3337 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003338 NO_STR
3339 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003340 "Reset syslog facility to default (daemon)\n"
3341 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003342{
ajs274a4a42004-12-07 15:39:31 +00003343 zlog_default->facility = LOG_DAEMON;
3344 return CMD_SUCCESS;
3345}
3346
3347DEFUN_DEPRECATED (config_log_trap,
3348 config_log_trap_cmd,
3349 "log trap "LOG_LEVELS,
3350 "Logging control\n"
3351 "(Deprecated) Set logging level and default for all destinations\n"
3352 LOG_LEVEL_DESC)
3353{
3354 int new_level ;
3355 int i;
3356
3357 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3358 return CMD_ERR_NO_MATCH;
3359
3360 zlog_default->default_lvl = new_level;
3361 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3362 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3363 zlog_default->maxlvl[i] = new_level;
3364 return CMD_SUCCESS;
3365}
3366
3367DEFUN_DEPRECATED (no_config_log_trap,
3368 no_config_log_trap_cmd,
3369 "no log trap [LEVEL]",
3370 NO_STR
3371 "Logging control\n"
3372 "Permit all logging information\n"
3373 "Logging level\n")
3374{
3375 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003376 return CMD_SUCCESS;
3377}
3378
3379DEFUN (config_log_record_priority,
3380 config_log_record_priority_cmd,
3381 "log record-priority",
3382 "Logging control\n"
3383 "Log the priority of the message within the message\n")
3384{
3385 zlog_default->record_priority = 1 ;
3386 return CMD_SUCCESS;
3387}
3388
3389DEFUN (no_config_log_record_priority,
3390 no_config_log_record_priority_cmd,
3391 "no log record-priority",
3392 NO_STR
3393 "Logging control\n"
3394 "Do not log the priority of the message within the message\n")
3395{
3396 zlog_default->record_priority = 0 ;
3397 return CMD_SUCCESS;
3398}
3399
3400
3401DEFUN (banner_motd_default,
3402 banner_motd_default_cmd,
3403 "banner motd default",
3404 "Set banner string\n"
3405 "Strings for motd\n"
3406 "Default string\n")
3407{
3408 host.motd = default_motd;
3409 return CMD_SUCCESS;
3410}
3411
3412DEFUN (no_banner_motd,
3413 no_banner_motd_cmd,
3414 "no banner motd",
3415 NO_STR
3416 "Set banner string\n"
3417 "Strings for motd\n")
3418{
3419 host.motd = NULL;
3420 return CMD_SUCCESS;
3421}
3422
3423/* Set config filename. Called from vty.c */
3424void
3425host_config_set (char *filename)
3426{
3427 host.config = strdup (filename);
3428}
3429
3430void
3431install_default (enum node_type node)
3432{
3433 install_element (node, &config_exit_cmd);
3434 install_element (node, &config_quit_cmd);
3435 install_element (node, &config_end_cmd);
3436 install_element (node, &config_help_cmd);
3437 install_element (node, &config_list_cmd);
3438
3439 install_element (node, &config_write_terminal_cmd);
3440 install_element (node, &config_write_file_cmd);
3441 install_element (node, &config_write_memory_cmd);
3442 install_element (node, &config_write_cmd);
3443 install_element (node, &show_running_config_cmd);
3444}
3445
3446/* Initialize command interface. Install basic nodes and commands. */
3447void
3448cmd_init (int terminal)
3449{
3450 /* Allocate initial top vector of commands. */
3451 cmdvec = vector_init (VECTOR_MIN_SIZE);
3452
3453 /* Default host value settings. */
3454 host.name = NULL;
3455 host.password = NULL;
3456 host.enable = NULL;
3457 host.logfile = NULL;
3458 host.config = NULL;
3459 host.lines = -1;
3460 host.motd = default_motd;
3461
3462 /* Install top nodes. */
3463 install_node (&view_node, NULL);
3464 install_node (&enable_node, NULL);
3465 install_node (&auth_node, NULL);
3466 install_node (&auth_enable_node, NULL);
3467 install_node (&config_node, config_write_host);
3468
3469 /* Each node's basic commands. */
3470 install_element (VIEW_NODE, &show_version_cmd);
3471 if (terminal)
3472 {
3473 install_element (VIEW_NODE, &config_list_cmd);
3474 install_element (VIEW_NODE, &config_exit_cmd);
3475 install_element (VIEW_NODE, &config_quit_cmd);
3476 install_element (VIEW_NODE, &config_help_cmd);
3477 install_element (VIEW_NODE, &config_enable_cmd);
3478 install_element (VIEW_NODE, &config_terminal_length_cmd);
3479 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003480 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003481 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003482 }
3483
3484 if (terminal)
3485 {
3486 install_default (ENABLE_NODE);
3487 install_element (ENABLE_NODE, &config_disable_cmd);
3488 install_element (ENABLE_NODE, &config_terminal_cmd);
3489 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3490 }
3491 install_element (ENABLE_NODE, &show_startup_config_cmd);
3492 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003493
3494 if (terminal)
paul718e3742002-12-13 20:15:29 +00003495 {
hassoe7168df2004-10-03 20:11:32 +00003496 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3497 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003498 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003499 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003500 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003501
3502 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003503 }
3504
3505 install_element (CONFIG_NODE, &hostname_cmd);
3506 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003507
hassoea8e9d92004-10-07 21:32:14 +00003508 if (terminal)
3509 {
hassoe7168df2004-10-03 20:11:32 +00003510 install_element (CONFIG_NODE, &password_cmd);
3511 install_element (CONFIG_NODE, &password_text_cmd);
3512 install_element (CONFIG_NODE, &enable_password_cmd);
3513 install_element (CONFIG_NODE, &enable_password_text_cmd);
3514 install_element (CONFIG_NODE, &no_enable_password_cmd);
3515
paul718e3742002-12-13 20:15:29 +00003516 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003517 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003518 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003519 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3520 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3521 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003522 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003523 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003524 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003525 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003526 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003527 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003528 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003529 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003530 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003531 install_element (CONFIG_NODE, &config_log_facility_cmd);
3532 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003533 install_element (CONFIG_NODE, &config_log_trap_cmd);
3534 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3535 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3536 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3537 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3538 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3539 install_element (CONFIG_NODE, &banner_motd_default_cmd);
3540 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3541 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3542 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003543
paul9ab68122003-01-18 01:16:20 +00003544 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3545 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3546 }
paul718e3742002-12-13 20:15:29 +00003547 srand(time(NULL));
3548}