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