blob: be38fcc009c1093875ed32944cc2ea73b9796dd2 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
ajsf6834d42005-01-28 20:28:35 +00002 $Id: command.c,v 1.36 2005/01/28 20:28:35 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;
ajsf6834d42005-01-28 20:28:35 +0000160 size_t len;
paul718e3742002-12-13 20:15:29 +0000161 char *str;
ajsf6834d42005-01-28 20:28:35 +0000162 char *p;
paul718e3742002-12-13 20:15:29 +0000163
ajsf6834d42005-01-28 20:28:35 +0000164 len = 0;
165 for (i = shift; i < argc; i++)
166 len += strlen(argv[i])+1;
167 if (!len)
168 return NULL;
169 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000170 for (i = shift; i < argc; i++)
171 {
ajsf6834d42005-01-28 20:28:35 +0000172 size_t arglen;
173 memcpy(p, argv[i], (arglen = strlen(argv[i])));
174 p += arglen;
175 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000176 }
ajsf6834d42005-01-28 20:28:35 +0000177 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000178 return str;
179}
180
181/* Install top node of command vector. */
182void
183install_node (struct cmd_node *node,
184 int (*func) (struct vty *))
185{
186 vector_set_index (cmdvec, node->node, node);
187 node->func = func;
188 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
189}
190
191/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000192static int
paul718e3742002-12-13 20:15:29 +0000193cmp_node (const void *p, const void *q)
194{
195 struct cmd_element *a = *(struct cmd_element **)p;
196 struct cmd_element *b = *(struct cmd_element **)q;
197
198 return strcmp (a->string, b->string);
199}
200
ajs274a4a42004-12-07 15:39:31 +0000201static int
paul718e3742002-12-13 20:15:29 +0000202cmp_desc (const void *p, const void *q)
203{
204 struct desc *a = *(struct desc **)p;
205 struct desc *b = *(struct desc **)q;
206
207 return strcmp (a->cmd, b->cmd);
208}
209
210/* Sort each node's command element according to command string. */
211void
212sort_node ()
213{
hasso8c328f12004-10-05 21:01:23 +0000214 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000215 struct cmd_node *cnode;
216 vector descvec;
217 struct cmd_element *cmd_element;
218
219 for (i = 0; i < vector_max (cmdvec); i++)
220 if ((cnode = vector_slot (cmdvec, i)) != NULL)
221 {
222 vector cmd_vector = cnode->cmd_vector;
223 qsort (cmd_vector->index, cmd_vector->max, sizeof (void *), cmp_node);
224
225 for (j = 0; j < vector_max (cmd_vector); j++)
226 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
227 {
228 descvec = vector_slot (cmd_element->strvec,
229 vector_max (cmd_element->strvec) - 1);
230 qsort (descvec->index, descvec->max, sizeof (void *), cmp_desc);
231 }
232 }
233}
234
235/* Breaking up string into each command piece. I assume given
236 character is separated by a space character. Return value is a
237 vector which includes char ** data element. */
238vector
hassoea8e9d92004-10-07 21:32:14 +0000239cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000240{
hassoea8e9d92004-10-07 21:32:14 +0000241 const char *cp, *start;
242 char *token;
paul718e3742002-12-13 20:15:29 +0000243 int strlen;
244 vector strvec;
245
246 if (string == NULL)
247 return NULL;
248
249 cp = string;
250
251 /* Skip white spaces. */
252 while (isspace ((int) *cp) && *cp != '\0')
253 cp++;
254
255 /* Return if there is only white spaces */
256 if (*cp == '\0')
257 return NULL;
258
259 if (*cp == '!' || *cp == '#')
260 return NULL;
261
262 /* Prepare return vector. */
263 strvec = vector_init (VECTOR_MIN_SIZE);
264
265 /* Copy each command piece and set into vector. */
266 while (1)
267 {
268 start = cp;
269 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
270 *cp != '\0')
271 cp++;
272 strlen = cp - start;
273 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
274 memcpy (token, start, strlen);
275 *(token + strlen) = '\0';
276 vector_set (strvec, token);
277
278 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
279 *cp != '\0')
280 cp++;
281
282 if (*cp == '\0')
283 return strvec;
284 }
285}
286
287/* Free allocated string vector. */
288void
289cmd_free_strvec (vector v)
290{
hasso8c328f12004-10-05 21:01:23 +0000291 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000292 char *cp;
293
294 if (!v)
295 return;
296
297 for (i = 0; i < vector_max (v); i++)
298 if ((cp = vector_slot (v, i)) != NULL)
299 XFREE (MTYPE_STRVEC, cp);
300
301 vector_free (v);
302}
303
304/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000305static char *
hasso6ad96ea2004-10-07 19:33:46 +0000306cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000307{
hasso6ad96ea2004-10-07 19:33:46 +0000308 const char *cp, *start;
309 char *token;
paul718e3742002-12-13 20:15:29 +0000310 int strlen;
311
312 cp = *string;
313
314 if (cp == NULL)
315 return NULL;
316
317 /* Skip white spaces. */
318 while (isspace ((int) *cp) && *cp != '\0')
319 cp++;
320
321 /* Return if there is only white spaces */
322 if (*cp == '\0')
323 return NULL;
324
325 start = cp;
326
327 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
328 cp++;
329
330 strlen = cp - start;
331 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
332 memcpy (token, start, strlen);
333 *(token + strlen) = '\0';
334
335 *string = cp;
336
337 return token;
338}
339
340/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000341static vector
hasso8c328f12004-10-05 21:01:23 +0000342cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000343{
344 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000345 const char *sp;
paul718e3742002-12-13 20:15:29 +0000346 char *token;
347 int len;
hasso8c328f12004-10-05 21:01:23 +0000348 const char *cp;
349 const char *dp;
paul718e3742002-12-13 20:15:29 +0000350 vector allvec;
351 vector strvec = NULL;
352 struct desc *desc;
353
354 cp = string;
355 dp = descstr;
356
357 if (cp == NULL)
358 return NULL;
359
360 allvec = vector_init (VECTOR_MIN_SIZE);
361
362 while (1)
363 {
364 while (isspace ((int) *cp) && *cp != '\0')
365 cp++;
366
367 if (*cp == '(')
368 {
369 multiple = 1;
370 cp++;
371 }
372 if (*cp == ')')
373 {
374 multiple = 0;
375 cp++;
376 }
377 if (*cp == '|')
378 {
379 if (! multiple)
380 {
381 fprintf (stderr, "Command parse error!: %s\n", string);
382 exit (1);
383 }
384 cp++;
385 }
386
387 while (isspace ((int) *cp) && *cp != '\0')
388 cp++;
389
390 if (*cp == '(')
391 {
392 multiple = 1;
393 cp++;
394 }
395
396 if (*cp == '\0')
397 return allvec;
398
399 sp = cp;
400
401 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
402 cp++;
403
404 len = cp - sp;
405
406 token = XMALLOC (MTYPE_STRVEC, len + 1);
407 memcpy (token, sp, len);
408 *(token + len) = '\0';
409
410 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
411 desc->cmd = token;
412 desc->str = cmd_desc_str (&dp);
413
414 if (multiple)
415 {
416 if (multiple == 1)
417 {
418 strvec = vector_init (VECTOR_MIN_SIZE);
419 vector_set (allvec, strvec);
420 }
421 multiple++;
422 }
423 else
424 {
425 strvec = vector_init (VECTOR_MIN_SIZE);
426 vector_set (allvec, strvec);
427 }
428 vector_set (strvec, desc);
429 }
430}
431
432/* Count mandantory string vector size. This is to determine inputed
433 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000434static int
paul718e3742002-12-13 20:15:29 +0000435cmd_cmdsize (vector strvec)
436{
hasso8c328f12004-10-05 21:01:23 +0000437 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000438 int size = 0;
439 vector descvec;
440
441 for (i = 0; i < vector_max (strvec); i++)
442 {
443 descvec = vector_slot (strvec, i);
444
445 if (vector_max (descvec) == 1)
446 {
447 struct desc *desc = vector_slot (descvec, 0);
448
hasso8c328f12004-10-05 21:01:23 +0000449 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000450 return size;
451 else
452 size++;
453 }
454 else
455 size++;
456 }
457 return size;
458}
459
460/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000461const char *
paul718e3742002-12-13 20:15:29 +0000462cmd_prompt (enum node_type node)
463{
464 struct cmd_node *cnode;
465
466 cnode = vector_slot (cmdvec, node);
467 return cnode->prompt;
468}
469
470/* Install a command into a node. */
471void
472install_element (enum node_type ntype, struct cmd_element *cmd)
473{
474 struct cmd_node *cnode;
475
476 cnode = vector_slot (cmdvec, ntype);
477
478 if (cnode == NULL)
479 {
480 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
481 ntype);
482 exit (1);
483 }
484
485 vector_set (cnode->cmd_vector, cmd);
486
487 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
488 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
489}
490
491static unsigned char itoa64[] =
492"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
493
ajs274a4a42004-12-07 15:39:31 +0000494static void
paul718e3742002-12-13 20:15:29 +0000495to64(char *s, long v, int n)
496{
497 while (--n >= 0)
498 {
499 *s++ = itoa64[v&0x3f];
500 v >>= 6;
501 }
502}
503
ajs274a4a42004-12-07 15:39:31 +0000504static char *
505zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000506{
507 char salt[6];
508 struct timeval tv;
509 char *crypt (const char *, const char *);
510
511 gettimeofday(&tv,0);
512
513 to64(&salt[0], random(), 3);
514 to64(&salt[3], tv.tv_usec, 3);
515 salt[5] = '\0';
516
517 return crypt (passwd, salt);
518}
519
520/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000521static int
paul718e3742002-12-13 20:15:29 +0000522config_write_host (struct vty *vty)
523{
524 if (host.name)
525 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
526
527 if (host.encrypt)
528 {
529 if (host.password_encrypt)
530 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
531 if (host.enable_encrypt)
532 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
533 }
534 else
535 {
536 if (host.password)
537 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
538 if (host.enable)
539 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
540 }
541
ajs274a4a42004-12-07 15:39:31 +0000542 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000543 {
544 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
545 VTY_NEWLINE);
546 vty_out (vty, "log trap %s%s",
547 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
548 }
paul718e3742002-12-13 20:15:29 +0000549
ajs274a4a42004-12-07 15:39:31 +0000550 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000551 {
ajs274a4a42004-12-07 15:39:31 +0000552 vty_out (vty, "log file %s", host.logfile);
553 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
554 vty_out (vty, " %s",
555 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000556 vty_out (vty, "%s", VTY_NEWLINE);
557 }
ajs274a4a42004-12-07 15:39:31 +0000558
559 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
560 {
561 vty_out (vty, "log stdout");
562 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
563 vty_out (vty, " %s",
564 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
565 vty_out (vty, "%s", VTY_NEWLINE);
566 }
567
568 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
569 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
570 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
571 vty_out(vty,"log monitor %s%s",
572 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
573
574 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
575 {
576 vty_out (vty, "log syslog");
577 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
578 vty_out (vty, " %s",
579 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
580 vty_out (vty, "%s", VTY_NEWLINE);
581 }
582
583 if (zlog_default->facility != LOG_DAEMON)
584 vty_out (vty, "log facility %s%s",
585 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000586
587 if (zlog_default->record_priority == 1)
588 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
589
590 if (host.advanced)
591 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
592
593 if (host.encrypt)
594 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
595
596 if (host.lines >= 0)
597 vty_out (vty, "service terminal-length %d%s", host.lines,
598 VTY_NEWLINE);
599
600 if (! host.motd)
601 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
602
603 return 1;
604}
605
606/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000607static vector
paul718e3742002-12-13 20:15:29 +0000608cmd_node_vector (vector v, enum node_type ntype)
609{
610 struct cmd_node *cnode = vector_slot (v, ntype);
611 return cnode->cmd_vector;
612}
613
ajs274a4a42004-12-07 15:39:31 +0000614#if 0
615/* Filter command vector by symbol. This function is not actually used;
616 * should it be deleted? */
617static int
paul718e3742002-12-13 20:15:29 +0000618cmd_filter_by_symbol (char *command, char *symbol)
619{
620 int i, lim;
621
622 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
623 {
624 i = 0;
625 lim = strlen (command);
626 while (i < lim)
627 {
628 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
629 return 1;
630 i++;
631 }
632 return 0;
633 }
634 if (strcmp (symbol, "STRING") == 0)
635 {
636 i = 0;
637 lim = strlen (command);
638 while (i < lim)
639 {
640 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
641 return 1;
642 i++;
643 }
644 return 0;
645 }
646 if (strcmp (symbol, "IFNAME") == 0)
647 {
648 i = 0;
649 lim = strlen (command);
650 while (i < lim)
651 {
652 if (! isalnum ((int) command[i]))
653 return 1;
654 i++;
655 }
656 return 0;
657 }
658 return 0;
659}
ajs274a4a42004-12-07 15:39:31 +0000660#endif
paul718e3742002-12-13 20:15:29 +0000661
662/* Completion match types. */
663enum match_type
664{
665 no_match,
666 extend_match,
667 ipv4_prefix_match,
668 ipv4_match,
669 ipv6_prefix_match,
670 ipv6_match,
671 range_match,
672 vararg_match,
673 partly_match,
674 exact_match
675};
676
ajs274a4a42004-12-07 15:39:31 +0000677static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000678cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000679{
hasso8c328f12004-10-05 21:01:23 +0000680 const char *sp;
paul718e3742002-12-13 20:15:29 +0000681 int dots = 0, nums = 0;
682 char buf[4];
683
684 if (str == NULL)
685 return partly_match;
686
687 for (;;)
688 {
689 memset (buf, 0, sizeof (buf));
690 sp = str;
691 while (*str != '\0')
692 {
693 if (*str == '.')
694 {
695 if (dots >= 3)
696 return no_match;
697
698 if (*(str + 1) == '.')
699 return no_match;
700
701 if (*(str + 1) == '\0')
702 return partly_match;
703
704 dots++;
705 break;
706 }
707 if (!isdigit ((int) *str))
708 return no_match;
709
710 str++;
711 }
712
713 if (str - sp > 3)
714 return no_match;
715
716 strncpy (buf, sp, str - sp);
717 if (atoi (buf) > 255)
718 return no_match;
719
720 nums++;
721
722 if (*str == '\0')
723 break;
724
725 str++;
726 }
727
728 if (nums < 4)
729 return partly_match;
730
731 return exact_match;
732}
733
ajs274a4a42004-12-07 15:39:31 +0000734static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000735cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000736{
hasso8c328f12004-10-05 21:01:23 +0000737 const char *sp;
paul718e3742002-12-13 20:15:29 +0000738 int dots = 0;
739 char buf[4];
740
741 if (str == NULL)
742 return partly_match;
743
744 for (;;)
745 {
746 memset (buf, 0, sizeof (buf));
747 sp = str;
748 while (*str != '\0' && *str != '/')
749 {
750 if (*str == '.')
751 {
752 if (dots == 3)
753 return no_match;
754
755 if (*(str + 1) == '.' || *(str + 1) == '/')
756 return no_match;
757
758 if (*(str + 1) == '\0')
759 return partly_match;
760
761 dots++;
762 break;
763 }
764
765 if (!isdigit ((int) *str))
766 return no_match;
767
768 str++;
769 }
770
771 if (str - sp > 3)
772 return no_match;
773
774 strncpy (buf, sp, str - sp);
775 if (atoi (buf) > 255)
776 return no_match;
777
778 if (dots == 3)
779 {
780 if (*str == '/')
781 {
782 if (*(str + 1) == '\0')
783 return partly_match;
784
785 str++;
786 break;
787 }
788 else if (*str == '\0')
789 return partly_match;
790 }
791
792 if (*str == '\0')
793 return partly_match;
794
795 str++;
796 }
797
798 sp = str;
799 while (*str != '\0')
800 {
801 if (!isdigit ((int) *str))
802 return no_match;
803
804 str++;
805 }
806
807 if (atoi (sp) > 32)
808 return no_match;
809
810 return exact_match;
811}
812
813#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
814#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
815#define STATE_START 1
816#define STATE_COLON 2
817#define STATE_DOUBLE 3
818#define STATE_ADDR 4
819#define STATE_DOT 5
820#define STATE_SLASH 6
821#define STATE_MASK 7
822
paul22e0a9e2003-07-11 17:55:46 +0000823#ifdef HAVE_IPV6
824
ajs274a4a42004-12-07 15:39:31 +0000825static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000826cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000827{
828 int state = STATE_START;
829 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000830 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000831 struct sockaddr_in6 sin6_dummy;
832 int ret;
paul718e3742002-12-13 20:15:29 +0000833
834 if (str == NULL)
835 return partly_match;
836
837 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
838 return no_match;
839
hasso726f9b22003-05-25 21:04:54 +0000840 /* use inet_pton that has a better support,
841 * for example inet_pton can support the automatic addresses:
842 * ::1.2.3.4
843 */
844 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
845
846 if (ret == 1)
847 return exact_match;
848
paul718e3742002-12-13 20:15:29 +0000849 while (*str != '\0')
850 {
851 switch (state)
852 {
853 case STATE_START:
854 if (*str == ':')
855 {
856 if (*(str + 1) != ':' && *(str + 1) != '\0')
857 return no_match;
858 colons--;
859 state = STATE_COLON;
860 }
861 else
862 {
863 sp = str;
864 state = STATE_ADDR;
865 }
866
867 continue;
868 case STATE_COLON:
869 colons++;
870 if (*(str + 1) == ':')
871 state = STATE_DOUBLE;
872 else
873 {
874 sp = str + 1;
875 state = STATE_ADDR;
876 }
877 break;
878 case STATE_DOUBLE:
879 if (double_colon)
880 return no_match;
881
882 if (*(str + 1) == ':')
883 return no_match;
884 else
885 {
886 if (*(str + 1) != '\0')
887 colons++;
888 sp = str + 1;
889 state = STATE_ADDR;
890 }
891
892 double_colon++;
893 nums++;
894 break;
895 case STATE_ADDR:
896 if (*(str + 1) == ':' || *(str + 1) == '\0')
897 {
898 if (str - sp > 3)
899 return no_match;
900
901 nums++;
902 state = STATE_COLON;
903 }
904 if (*(str + 1) == '.')
905 state = STATE_DOT;
906 break;
907 case STATE_DOT:
908 state = STATE_ADDR;
909 break;
910 default:
911 break;
912 }
913
914 if (nums > 8)
915 return no_match;
916
917 if (colons > 7)
918 return no_match;
919
920 str++;
921 }
922
923#if 0
924 if (nums < 11)
925 return partly_match;
926#endif /* 0 */
927
928 return exact_match;
929}
930
ajs274a4a42004-12-07 15:39:31 +0000931static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000932cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000933{
934 int state = STATE_START;
935 int colons = 0, nums = 0, double_colon = 0;
936 int mask;
hasso8c328f12004-10-05 21:01:23 +0000937 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000938 char *endptr = NULL;
939
940 if (str == NULL)
941 return partly_match;
942
943 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
944 return no_match;
945
946 while (*str != '\0' && state != STATE_MASK)
947 {
948 switch (state)
949 {
950 case STATE_START:
951 if (*str == ':')
952 {
953 if (*(str + 1) != ':' && *(str + 1) != '\0')
954 return no_match;
955 colons--;
956 state = STATE_COLON;
957 }
958 else
959 {
960 sp = str;
961 state = STATE_ADDR;
962 }
963
964 continue;
965 case STATE_COLON:
966 colons++;
967 if (*(str + 1) == '/')
968 return no_match;
969 else if (*(str + 1) == ':')
970 state = STATE_DOUBLE;
971 else
972 {
973 sp = str + 1;
974 state = STATE_ADDR;
975 }
976 break;
977 case STATE_DOUBLE:
978 if (double_colon)
979 return no_match;
980
981 if (*(str + 1) == ':')
982 return no_match;
983 else
984 {
985 if (*(str + 1) != '\0' && *(str + 1) != '/')
986 colons++;
987 sp = str + 1;
988
989 if (*(str + 1) == '/')
990 state = STATE_SLASH;
991 else
992 state = STATE_ADDR;
993 }
994
995 double_colon++;
996 nums += 1;
997 break;
998 case STATE_ADDR:
999 if (*(str + 1) == ':' || *(str + 1) == '.'
1000 || *(str + 1) == '\0' || *(str + 1) == '/')
1001 {
1002 if (str - sp > 3)
1003 return no_match;
1004
1005 for (; sp <= str; sp++)
1006 if (*sp == '/')
1007 return no_match;
1008
1009 nums++;
1010
1011 if (*(str + 1) == ':')
1012 state = STATE_COLON;
1013 else if (*(str + 1) == '.')
1014 state = STATE_DOT;
1015 else if (*(str + 1) == '/')
1016 state = STATE_SLASH;
1017 }
1018 break;
1019 case STATE_DOT:
1020 state = STATE_ADDR;
1021 break;
1022 case STATE_SLASH:
1023 if (*(str + 1) == '\0')
1024 return partly_match;
1025
1026 state = STATE_MASK;
1027 break;
1028 default:
1029 break;
1030 }
1031
1032 if (nums > 11)
1033 return no_match;
1034
1035 if (colons > 7)
1036 return no_match;
1037
1038 str++;
1039 }
1040
1041 if (state < STATE_MASK)
1042 return partly_match;
1043
1044 mask = strtol (str, &endptr, 10);
1045 if (*endptr != '\0')
1046 return no_match;
1047
1048 if (mask < 0 || mask > 128)
1049 return no_match;
1050
1051/* I don't know why mask < 13 makes command match partly.
1052 Forgive me to make this comments. I Want to set static default route
1053 because of lack of function to originate default in ospf6d; sorry
1054 yasu
1055 if (mask < 13)
1056 return partly_match;
1057*/
1058
1059 return exact_match;
1060}
1061
paul22e0a9e2003-07-11 17:55:46 +00001062#endif /* HAVE_IPV6 */
1063
paul718e3742002-12-13 20:15:29 +00001064#define DECIMAL_STRLEN_MAX 10
1065
ajs274a4a42004-12-07 15:39:31 +00001066static int
hasso8c328f12004-10-05 21:01:23 +00001067cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001068{
1069 char *p;
1070 char buf[DECIMAL_STRLEN_MAX + 1];
1071 char *endptr = NULL;
1072 unsigned long min, max, val;
1073
1074 if (str == NULL)
1075 return 1;
1076
1077 val = strtoul (str, &endptr, 10);
1078 if (*endptr != '\0')
1079 return 0;
1080
1081 range++;
1082 p = strchr (range, '-');
1083 if (p == NULL)
1084 return 0;
1085 if (p - range > DECIMAL_STRLEN_MAX)
1086 return 0;
1087 strncpy (buf, range, p - range);
1088 buf[p - range] = '\0';
1089 min = strtoul (buf, &endptr, 10);
1090 if (*endptr != '\0')
1091 return 0;
1092
1093 range = p + 1;
1094 p = strchr (range, '>');
1095 if (p == NULL)
1096 return 0;
1097 if (p - range > DECIMAL_STRLEN_MAX)
1098 return 0;
1099 strncpy (buf, range, p - range);
1100 buf[p - range] = '\0';
1101 max = strtoul (buf, &endptr, 10);
1102 if (*endptr != '\0')
1103 return 0;
1104
1105 if (val < min || val > max)
1106 return 0;
1107
1108 return 1;
1109}
1110
1111/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001112static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001113cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001114{
hasso8c328f12004-10-05 21:01:23 +00001115 unsigned int i;
1116 const char *str;
paul718e3742002-12-13 20:15:29 +00001117 struct cmd_element *cmd_element;
1118 enum match_type match_type;
1119 vector descvec;
1120 struct desc *desc;
1121
1122 match_type = no_match;
1123
1124 /* If command and cmd_element string does not match set NULL to vector */
1125 for (i = 0; i < vector_max (v); i++)
1126 if ((cmd_element = vector_slot (v, i)) != NULL)
1127 {
1128 if (index >= vector_max (cmd_element->strvec))
1129 vector_slot (v, i) = NULL;
1130 else
1131 {
hasso8c328f12004-10-05 21:01:23 +00001132 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001133 int matched = 0;
1134
1135 descvec = vector_slot (cmd_element->strvec, index);
1136
1137 for (j = 0; j < vector_max (descvec); j++)
1138 {
1139 desc = vector_slot (descvec, j);
1140 str = desc->cmd;
1141
1142 if (CMD_VARARG (str))
1143 {
1144 if (match_type < vararg_match)
1145 match_type = vararg_match;
1146 matched++;
1147 }
1148 else if (CMD_RANGE (str))
1149 {
1150 if (cmd_range_match (str, command))
1151 {
1152 if (match_type < range_match)
1153 match_type = range_match;
1154
1155 matched++;
1156 }
1157 }
paul22e0a9e2003-07-11 17:55:46 +00001158#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001159 else if (CMD_IPV6 (str))
1160 {
1161 if (cmd_ipv6_match (command))
1162 {
1163 if (match_type < ipv6_match)
1164 match_type = ipv6_match;
1165
1166 matched++;
1167 }
1168 }
1169 else if (CMD_IPV6_PREFIX (str))
1170 {
1171 if (cmd_ipv6_prefix_match (command))
1172 {
1173 if (match_type < ipv6_prefix_match)
1174 match_type = ipv6_prefix_match;
1175
1176 matched++;
1177 }
1178 }
paul22e0a9e2003-07-11 17:55:46 +00001179#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001180 else if (CMD_IPV4 (str))
1181 {
1182 if (cmd_ipv4_match (command))
1183 {
1184 if (match_type < ipv4_match)
1185 match_type = ipv4_match;
1186
1187 matched++;
1188 }
1189 }
1190 else if (CMD_IPV4_PREFIX (str))
1191 {
1192 if (cmd_ipv4_prefix_match (command))
1193 {
1194 if (match_type < ipv4_prefix_match)
1195 match_type = ipv4_prefix_match;
1196 matched++;
1197 }
1198 }
1199 else
1200 /* Check is this point's argument optional ? */
1201 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1202 {
1203 if (match_type < extend_match)
1204 match_type = extend_match;
1205 matched++;
1206 }
1207 else if (strncmp (command, str, strlen (command)) == 0)
1208 {
1209 if (strcmp (command, str) == 0)
1210 match_type = exact_match;
1211 else
1212 {
1213 if (match_type < partly_match)
1214 match_type = partly_match;
1215 }
1216 matched++;
1217 }
1218 }
1219 if (! matched)
1220 vector_slot (v, i) = NULL;
1221 }
1222 }
1223 return match_type;
1224}
1225
1226/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001227static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001228cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001229{
hasso8c328f12004-10-05 21:01:23 +00001230 unsigned int i;
1231 const char *str;
paul718e3742002-12-13 20:15:29 +00001232 struct cmd_element *cmd_element;
1233 enum match_type match_type;
1234 vector descvec;
1235 struct desc *desc;
1236
1237 match_type = no_match;
1238
1239 /* If command and cmd_element string does not match set NULL to vector */
1240 for (i = 0; i < vector_max (v); i++)
1241 if ((cmd_element = vector_slot (v, i)) != NULL)
1242 {
1243 /* If given index is bigger than max string vector of command,
1244 set NULL*/
1245 if (index >= vector_max (cmd_element->strvec))
1246 vector_slot (v, i) = NULL;
1247 else
1248 {
hasso8c328f12004-10-05 21:01:23 +00001249 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001250 int matched = 0;
1251
1252 descvec = vector_slot (cmd_element->strvec, index);
1253
1254 for (j = 0; j < vector_max (descvec); j++)
1255 {
1256 desc = vector_slot (descvec, j);
1257 str = desc->cmd;
1258
1259 if (CMD_VARARG (str))
1260 {
1261 if (match_type < vararg_match)
1262 match_type = vararg_match;
1263 matched++;
1264 }
1265 else if (CMD_RANGE (str))
1266 {
1267 if (cmd_range_match (str, command))
1268 {
1269 if (match_type < range_match)
1270 match_type = range_match;
1271 matched++;
1272 }
1273 }
paul22e0a9e2003-07-11 17:55:46 +00001274#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001275 else if (CMD_IPV6 (str))
1276 {
1277 if (cmd_ipv6_match (command) == exact_match)
1278 {
1279 if (match_type < ipv6_match)
1280 match_type = ipv6_match;
1281 matched++;
1282 }
1283 }
1284 else if (CMD_IPV6_PREFIX (str))
1285 {
1286 if (cmd_ipv6_prefix_match (command) == exact_match)
1287 {
1288 if (match_type < ipv6_prefix_match)
1289 match_type = ipv6_prefix_match;
1290 matched++;
1291 }
1292 }
paul22e0a9e2003-07-11 17:55:46 +00001293#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001294 else if (CMD_IPV4 (str))
1295 {
1296 if (cmd_ipv4_match (command) == exact_match)
1297 {
1298 if (match_type < ipv4_match)
1299 match_type = ipv4_match;
1300 matched++;
1301 }
1302 }
1303 else if (CMD_IPV4_PREFIX (str))
1304 {
1305 if (cmd_ipv4_prefix_match (command) == exact_match)
1306 {
1307 if (match_type < ipv4_prefix_match)
1308 match_type = ipv4_prefix_match;
1309 matched++;
1310 }
1311 }
1312 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1313 {
1314 if (match_type < extend_match)
1315 match_type = extend_match;
1316 matched++;
1317 }
1318 else
1319 {
1320 if (strcmp (command, str) == 0)
1321 {
1322 match_type = exact_match;
1323 matched++;
1324 }
1325 }
1326 }
1327 if (! matched)
1328 vector_slot (v, i) = NULL;
1329 }
1330 }
1331 return match_type;
1332}
1333
1334/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001335static int
paul718e3742002-12-13 20:15:29 +00001336is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1337{
hasso8c328f12004-10-05 21:01:23 +00001338 unsigned int i;
1339 unsigned int j;
1340 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001341 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001342 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001343 vector descvec;
1344 struct desc *desc;
1345
1346 for (i = 0; i < vector_max (v); i++)
1347 if ((cmd_element = vector_slot (v, i)) != NULL)
1348 {
1349 int match = 0;
1350
1351 descvec = vector_slot (cmd_element->strvec, index);
1352
1353 for (j = 0; j < vector_max (descvec); j++)
1354 {
1355 enum match_type ret;
1356
1357 desc = vector_slot (descvec, j);
1358 str = desc->cmd;
1359
1360 switch (type)
1361 {
1362 case exact_match:
1363 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1364 && strcmp (command, str) == 0)
1365 match++;
1366 break;
1367 case partly_match:
1368 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1369 && strncmp (command, str, strlen (command)) == 0)
1370 {
1371 if (matched && strcmp (matched, str) != 0)
1372 return 1; /* There is ambiguous match. */
1373 else
1374 matched = str;
1375 match++;
1376 }
1377 break;
1378 case range_match:
1379 if (cmd_range_match (str, command))
1380 {
1381 if (matched && strcmp (matched, str) != 0)
1382 return 1;
1383 else
1384 matched = str;
1385 match++;
1386 }
1387 break;
paul22e0a9e2003-07-11 17:55:46 +00001388#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001389 case ipv6_match:
1390 if (CMD_IPV6 (str))
1391 match++;
1392 break;
1393 case ipv6_prefix_match:
1394 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1395 {
1396 if (ret == partly_match)
1397 return 2; /* There is incomplete match. */
1398
1399 match++;
1400 }
1401 break;
paul22e0a9e2003-07-11 17:55:46 +00001402#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001403 case ipv4_match:
1404 if (CMD_IPV4 (str))
1405 match++;
1406 break;
1407 case ipv4_prefix_match:
1408 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1409 {
1410 if (ret == partly_match)
1411 return 2; /* There is incomplete match. */
1412
1413 match++;
1414 }
1415 break;
1416 case extend_match:
1417 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1418 match++;
1419 break;
1420 case no_match:
1421 default:
1422 break;
1423 }
1424 }
1425 if (! match)
1426 vector_slot (v, i) = NULL;
1427 }
1428 return 0;
1429}
1430
1431/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001432static const char *
hasso8c328f12004-10-05 21:01:23 +00001433cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001434{
1435 /* Skip variable arguments. */
1436 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1437 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1438 return NULL;
1439
1440 /* In case of 'command \t', given src is NULL string. */
1441 if (src == NULL)
1442 return dst;
1443
1444 /* Matched with input string. */
1445 if (strncmp (src, dst, strlen (src)) == 0)
1446 return dst;
1447
1448 return NULL;
1449}
1450
1451/* If src matches dst return dst string, otherwise return NULL */
1452/* This version will return the dst string always if it is
1453 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001454static const char *
hasso8c328f12004-10-05 21:01:23 +00001455cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001456{
1457 if (CMD_VARARG (dst))
1458 return dst;
1459
1460 if (CMD_RANGE (dst))
1461 {
1462 if (cmd_range_match (dst, src))
1463 return dst;
1464 else
1465 return NULL;
1466 }
1467
paul22e0a9e2003-07-11 17:55:46 +00001468#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001469 if (CMD_IPV6 (dst))
1470 {
1471 if (cmd_ipv6_match (src))
1472 return dst;
1473 else
1474 return NULL;
1475 }
1476
1477 if (CMD_IPV6_PREFIX (dst))
1478 {
1479 if (cmd_ipv6_prefix_match (src))
1480 return dst;
1481 else
1482 return NULL;
1483 }
paul22e0a9e2003-07-11 17:55:46 +00001484#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001485
1486 if (CMD_IPV4 (dst))
1487 {
1488 if (cmd_ipv4_match (src))
1489 return dst;
1490 else
1491 return NULL;
1492 }
1493
1494 if (CMD_IPV4_PREFIX (dst))
1495 {
1496 if (cmd_ipv4_prefix_match (src))
1497 return dst;
1498 else
1499 return NULL;
1500 }
1501
1502 /* Optional or variable commands always match on '?' */
1503 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1504 return dst;
1505
1506 /* In case of 'command \t', given src is NULL string. */
1507 if (src == NULL)
1508 return dst;
1509
1510 if (strncmp (src, dst, strlen (src)) == 0)
1511 return dst;
1512 else
1513 return NULL;
1514}
1515
1516/* Check same string element existence. If it isn't there return
1517 1. */
ajs274a4a42004-12-07 15:39:31 +00001518static int
hasso8c328f12004-10-05 21:01:23 +00001519cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001520{
hasso8c328f12004-10-05 21:01:23 +00001521 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001522 char *match;
1523
1524 for (i = 0; i < vector_max (v); i++)
1525 if ((match = vector_slot (v, i)) != NULL)
1526 if (strcmp (match, str) == 0)
1527 return 0;
1528 return 1;
1529}
1530
1531/* Compare string to description vector. If there is same string
1532 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001533static int
hasso8c328f12004-10-05 21:01:23 +00001534desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001535{
hasso8c328f12004-10-05 21:01:23 +00001536 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001537 struct desc *desc;
1538
1539 for (i = 0; i < vector_max (v); i++)
1540 if ((desc = vector_slot (v, i)) != NULL)
1541 if (strcmp (desc->cmd, str) == 0)
1542 return 1;
1543 return 0;
1544}
1545
ajs274a4a42004-12-07 15:39:31 +00001546static int
paulb92938a2002-12-13 21:20:42 +00001547cmd_try_do_shortcut (enum node_type node, char* first_word) {
1548 if ( first_word != NULL &&
1549 node != AUTH_NODE &&
1550 node != VIEW_NODE &&
1551 node != AUTH_ENABLE_NODE &&
1552 node != ENABLE_NODE &&
1553 0 == strcmp( "do", first_word ) )
1554 return 1;
1555 return 0;
1556}
1557
paul718e3742002-12-13 20:15:29 +00001558/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001559static vector
paulb92938a2002-12-13 21:20:42 +00001560cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001561{
hassocba8a602005-01-02 18:51:01 +00001562 int i;
paul718e3742002-12-13 20:15:29 +00001563 vector cmd_vector;
1564#define INIT_MATCHVEC_SIZE 10
1565 vector matchvec;
1566 struct cmd_element *cmd_element;
hassocba8a602005-01-02 18:51:01 +00001567 int index;
paul54aba542003-08-21 20:28:24 +00001568 int ret;
1569 enum match_type match;
1570 char *command;
paul718e3742002-12-13 20:15:29 +00001571 static struct desc desc_cr = { "<cr>", "" };
1572
1573 /* Set index. */
1574 index = vector_max (vline) - 1;
1575
1576 /* Make copy vector of current node's command vector. */
1577 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1578
1579 /* Prepare match vector */
1580 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1581
1582 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001583 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001584 for (i = 0; i < index; i++)
1585 {
paul718e3742002-12-13 20:15:29 +00001586 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00001587 match = cmd_filter_by_completion (command, cmd_vector, i);
1588
1589 if (match == vararg_match)
1590 {
1591 struct cmd_element *cmd_element;
1592 vector descvec;
hasso8c328f12004-10-05 21:01:23 +00001593 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001594
1595 for (j = 0; j < vector_max (cmd_vector); j++)
1596 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1597 {
1598 descvec = vector_slot (cmd_element->strvec,
1599 vector_max (cmd_element->strvec) - 1);
1600 for (k = 0; k < vector_max (descvec); k++)
1601 {
1602 struct desc *desc = vector_slot (descvec, k);
1603 vector_set (matchvec, desc);
1604 }
1605 }
1606
1607 vector_set (matchvec, &desc_cr);
paul718e3742002-12-13 20:15:29 +00001608 vector_free (cmd_vector);
1609
1610 return matchvec;
1611 }
1612
1613 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1614 {
1615 vector_free (cmd_vector);
1616 *status = CMD_ERR_AMBIGUOUS;
1617 return NULL;
1618 }
1619 else if (ret == 2)
1620 {
1621 vector_free (cmd_vector);
1622 *status = CMD_ERR_NO_MATCH;
1623 return NULL;
1624 }
1625 }
1626
1627 /* Prepare match vector */
1628 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1629
paul54aba542003-08-21 20:28:24 +00001630 /* Make sure that cmd_vector is filtered based on current word */
1631 command = vector_slot (vline, index);
1632 if (command)
1633 match = cmd_filter_by_completion (command, cmd_vector, index);
1634
paul718e3742002-12-13 20:15:29 +00001635 /* Make description vector. */
1636 for (i = 0; i < vector_max (cmd_vector); i++)
1637 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1638 {
hasso8c328f12004-10-05 21:01:23 +00001639 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001640 vector strvec = cmd_element->strvec;
1641
paul54aba542003-08-21 20:28:24 +00001642 /* if command is NULL, index may be equal to vector_max */
1643 if (command && index >= vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001644 vector_slot (cmd_vector, i) = NULL;
1645 else
1646 {
paul54aba542003-08-21 20:28:24 +00001647 /* Check if command is completed. */
1648 if (command == NULL && index == vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001649 {
1650 string = "<cr>";
1651 if (! desc_unique_string (matchvec, string))
1652 vector_set (matchvec, &desc_cr);
1653 }
1654 else
1655 {
hasso8c328f12004-10-05 21:01:23 +00001656 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001657 vector descvec = vector_slot (strvec, index);
1658 struct desc *desc;
1659
1660 for (j = 0; j < vector_max (descvec); j++)
1661 {
1662 desc = vector_slot (descvec, j);
paul54aba542003-08-21 20:28:24 +00001663 string = cmd_entry_function_desc (command, desc->cmd);
paul718e3742002-12-13 20:15:29 +00001664 if (string)
1665 {
1666 /* Uniqueness check */
1667 if (! desc_unique_string (matchvec, string))
1668 vector_set (matchvec, desc);
1669 }
1670 }
1671 }
1672 }
1673 }
1674 vector_free (cmd_vector);
1675
1676 if (vector_slot (matchvec, 0) == NULL)
1677 {
1678 vector_free (matchvec);
1679 *status= CMD_ERR_NO_MATCH;
1680 }
1681 else
1682 *status = CMD_SUCCESS;
1683
1684 return matchvec;
1685}
1686
paulb92938a2002-12-13 21:20:42 +00001687vector
1688cmd_describe_command (vector vline, struct vty *vty, int *status)
1689{
1690 vector ret;
1691
1692 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1693 {
1694 enum node_type onode;
1695 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001696 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001697
1698 onode = vty->node;
1699 vty->node = ENABLE_NODE;
1700 /* We can try it on enable node, cos' the vty is authenticated */
1701
1702 shifted_vline = vector_init (vector_count(vline));
1703 /* use memcpy? */
1704 for (index = 1; index < vector_max (vline); index++)
1705 {
1706 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1707 }
1708
1709 ret = cmd_describe_command_real (shifted_vline, vty, status);
1710
1711 vector_free(shifted_vline);
1712 vty->node = onode;
1713 return ret;
1714 }
1715
1716
1717 return cmd_describe_command_real (vline, vty, status);
1718}
1719
1720
paul718e3742002-12-13 20:15:29 +00001721/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001722static int
paul718e3742002-12-13 20:15:29 +00001723cmd_lcd (char **matched)
1724{
1725 int i;
1726 int j;
1727 int lcd = -1;
1728 char *s1, *s2;
1729 char c1, c2;
1730
1731 if (matched[0] == NULL || matched[1] == NULL)
1732 return 0;
1733
1734 for (i = 1; matched[i] != NULL; i++)
1735 {
1736 s1 = matched[i - 1];
1737 s2 = matched[i];
1738
1739 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1740 if (c1 != c2)
1741 break;
1742
1743 if (lcd < 0)
1744 lcd = j;
1745 else
1746 {
1747 if (lcd > j)
1748 lcd = j;
1749 }
1750 }
1751 return lcd;
1752}
1753
1754/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001755static char **
paulb92938a2002-12-13 21:20:42 +00001756cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001757{
hassocba8a602005-01-02 18:51:01 +00001758 int i;
paul718e3742002-12-13 20:15:29 +00001759 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1760#define INIT_MATCHVEC_SIZE 10
1761 vector matchvec;
1762 struct cmd_element *cmd_element;
hassocba8a602005-01-02 18:51:01 +00001763 int index = vector_max (vline) - 1;
paul718e3742002-12-13 20:15:29 +00001764 char **match_str;
1765 struct desc *desc;
1766 vector descvec;
1767 char *command;
1768 int lcd;
1769
1770 /* First, filter by preceeding command string */
1771 for (i = 0; i < index; i++)
1772 {
1773 enum match_type match;
1774 int ret;
1775
1776 command = vector_slot (vline, i);
1777
1778 /* First try completion match, if there is exactly match return 1 */
1779 match = cmd_filter_by_completion (command, cmd_vector, i);
1780
1781 /* If there is exact match then filter ambiguous match else check
1782 ambiguousness. */
1783 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1784 {
1785 vector_free (cmd_vector);
1786 *status = CMD_ERR_AMBIGUOUS;
1787 return NULL;
1788 }
1789 /*
1790 else if (ret == 2)
1791 {
1792 vector_free (cmd_vector);
1793 *status = CMD_ERR_NO_MATCH;
1794 return NULL;
1795 }
1796 */
1797 }
1798
1799 /* Prepare match vector. */
1800 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1801
1802 /* Now we got into completion */
1803 for (i = 0; i < vector_max (cmd_vector); i++)
1804 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1805 {
hasso8c328f12004-10-05 21:01:23 +00001806 const char *string;
paul718e3742002-12-13 20:15:29 +00001807 vector strvec = cmd_element->strvec;
1808
1809 /* Check field length */
1810 if (index >= vector_max (strvec))
1811 vector_slot (cmd_vector, i) = NULL;
1812 else
1813 {
hasso8c328f12004-10-05 21:01:23 +00001814 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001815
1816 descvec = vector_slot (strvec, index);
1817 for (j = 0; j < vector_max (descvec); j++)
1818 {
1819 desc = vector_slot (descvec, j);
1820
1821 if ((string = cmd_entry_function (vector_slot (vline, index),
1822 desc->cmd)))
1823 if (cmd_unique_string (matchvec, string))
1824 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1825 }
1826 }
1827 }
1828
1829 /* We don't need cmd_vector any more. */
1830 vector_free (cmd_vector);
1831
1832 /* No matched command */
1833 if (vector_slot (matchvec, 0) == NULL)
1834 {
1835 vector_free (matchvec);
1836
1837 /* In case of 'command \t' pattern. Do you need '?' command at
1838 the end of the line. */
1839 if (vector_slot (vline, index) == '\0')
1840 *status = CMD_ERR_NOTHING_TODO;
1841 else
1842 *status = CMD_ERR_NO_MATCH;
1843 return NULL;
1844 }
1845
1846 /* Only one matched */
1847 if (vector_slot (matchvec, 1) == NULL)
1848 {
1849 match_str = (char **) matchvec->index;
1850 vector_only_wrapper_free (matchvec);
1851 *status = CMD_COMPLETE_FULL_MATCH;
1852 return match_str;
1853 }
1854 /* Make it sure last element is NULL. */
1855 vector_set (matchvec, NULL);
1856
1857 /* Check LCD of matched strings. */
1858 if (vector_slot (vline, index) != NULL)
1859 {
1860 lcd = cmd_lcd ((char **) matchvec->index);
1861
1862 if (lcd)
1863 {
1864 int len = strlen (vector_slot (vline, index));
1865
1866 if (len < lcd)
1867 {
1868 char *lcdstr;
1869
1870 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1871 memcpy (lcdstr, matchvec->index[0], lcd);
1872 lcdstr[lcd] = '\0';
1873
1874 /* match_str = (char **) &lcdstr; */
1875
1876 /* Free matchvec. */
1877 for (i = 0; i < vector_max (matchvec); i++)
1878 {
1879 if (vector_slot (matchvec, i))
1880 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1881 }
1882 vector_free (matchvec);
1883
1884 /* Make new matchvec. */
1885 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1886 vector_set (matchvec, lcdstr);
1887 match_str = (char **) matchvec->index;
1888 vector_only_wrapper_free (matchvec);
1889
1890 *status = CMD_COMPLETE_MATCH;
1891 return match_str;
1892 }
1893 }
1894 }
1895
1896 match_str = (char **) matchvec->index;
1897 vector_only_wrapper_free (matchvec);
1898 *status = CMD_COMPLETE_LIST_MATCH;
1899 return match_str;
1900}
1901
paulb92938a2002-12-13 21:20:42 +00001902char **
paul9ab68122003-01-18 01:16:20 +00001903cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001904{
1905 char **ret;
1906
1907 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1908 {
1909 enum node_type onode;
1910 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001911 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001912
1913 onode = vty->node;
1914 vty->node = ENABLE_NODE;
1915 /* We can try it on enable node, cos' the vty is authenticated */
1916
1917 shifted_vline = vector_init (vector_count(vline));
1918 /* use memcpy? */
1919 for (index = 1; index < vector_max (vline); index++)
1920 {
1921 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1922 }
1923
1924 ret = cmd_complete_command_real (shifted_vline, vty, status);
1925
1926 vector_free(shifted_vline);
1927 vty->node = onode;
1928 return ret;
1929 }
1930
1931
1932 return cmd_complete_command_real (vline, vty, status);
1933}
1934
1935/* return parent node */
1936/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001937enum node_type
ajs274a4a42004-12-07 15:39:31 +00001938node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001939{
1940 enum node_type ret;
1941
paul9ab68122003-01-18 01:16:20 +00001942 assert (node > CONFIG_NODE);
1943
1944 switch (node)
1945 {
1946 case BGP_VPNV4_NODE:
1947 case BGP_IPV4_NODE:
1948 case BGP_IPV4M_NODE:
1949 case BGP_IPV6_NODE:
1950 ret = BGP_NODE;
1951 break;
1952 case KEYCHAIN_KEY_NODE:
1953 ret = KEYCHAIN_NODE;
1954 break;
1955 default:
1956 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001957 }
1958
1959 return ret;
1960}
1961
paul718e3742002-12-13 20:15:29 +00001962/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001963static int
paulb92938a2002-12-13 21:20:42 +00001964cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001965{
hasso8c328f12004-10-05 21:01:23 +00001966 unsigned int i;
1967 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001968 vector cmd_vector;
1969 struct cmd_element *cmd_element;
1970 struct cmd_element *matched_element;
1971 unsigned int matched_count, incomplete_count;
1972 int argc;
paul9035efa2004-10-10 11:56:56 +00001973 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001974 enum match_type match = 0;
1975 int varflag;
1976 char *command;
1977
1978 /* Make copy of command elements. */
1979 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1980
1981 for (index = 0; index < vector_max (vline); index++)
1982 {
1983 int ret;
1984
1985 command = vector_slot (vline, index);
1986
1987 match = cmd_filter_by_completion (command, cmd_vector, index);
1988
1989 if (match == vararg_match)
1990 break;
1991
1992 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1993
1994 if (ret == 1)
1995 {
1996 vector_free (cmd_vector);
1997 return CMD_ERR_AMBIGUOUS;
1998 }
1999 else if (ret == 2)
2000 {
2001 vector_free (cmd_vector);
2002 return CMD_ERR_NO_MATCH;
2003 }
2004 }
2005
2006 /* Check matched count. */
2007 matched_element = NULL;
2008 matched_count = 0;
2009 incomplete_count = 0;
2010
2011 for (i = 0; i < vector_max (cmd_vector); i++)
2012 if (vector_slot (cmd_vector,i) != NULL)
2013 {
2014 cmd_element = vector_slot (cmd_vector,i);
2015
2016 if (match == vararg_match || index >= cmd_element->cmdsize)
2017 {
2018 matched_element = cmd_element;
2019#if 0
2020 printf ("DEBUG: %s\n", cmd_element->string);
2021#endif
2022 matched_count++;
2023 }
2024 else
2025 {
2026 incomplete_count++;
2027 }
2028 }
2029
2030 /* Finish of using cmd_vector. */
2031 vector_free (cmd_vector);
2032
2033 /* To execute command, matched_count must be 1.*/
2034 if (matched_count == 0)
2035 {
2036 if (incomplete_count)
2037 return CMD_ERR_INCOMPLETE;
2038 else
2039 return CMD_ERR_NO_MATCH;
2040 }
2041
2042 if (matched_count > 1)
2043 return CMD_ERR_AMBIGUOUS;
2044
2045 /* Argument treatment */
2046 varflag = 0;
2047 argc = 0;
2048
2049 for (i = 0; i < vector_max (vline); i++)
2050 {
2051 if (varflag)
2052 argv[argc++] = vector_slot (vline, i);
2053 else
2054 {
2055 vector descvec = vector_slot (matched_element->strvec, i);
2056
2057 if (vector_max (descvec) == 1)
2058 {
2059 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002060
hasso8c328f12004-10-05 21:01:23 +00002061 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002062 varflag = 1;
2063
hasso8c328f12004-10-05 21:01:23 +00002064 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002065 argv[argc++] = vector_slot (vline, i);
2066 }
2067 else
2068 argv[argc++] = vector_slot (vline, i);
2069 }
2070
2071 if (argc >= CMD_ARGC_MAX)
2072 return CMD_ERR_EXEED_ARGC_MAX;
2073 }
2074
2075 /* For vtysh execution. */
2076 if (cmd)
2077 *cmd = matched_element;
2078
2079 if (matched_element->daemon)
2080 return CMD_SUCCESS_DAEMON;
2081
2082 /* Execute matched command. */
2083 return (*matched_element->func) (matched_element, vty, argc, argv);
2084}
2085
paulb92938a2002-12-13 21:20:42 +00002086
2087int
hasso87d683b2005-01-16 23:31:54 +00002088cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2089 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002090 int ret, saved_ret, tried = 0;
2091 enum node_type onode, try_node;
2092
2093 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002094
2095 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2096 {
2097 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002098 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002099
2100 vty->node = ENABLE_NODE;
2101 /* We can try it on enable node, cos' the vty is authenticated */
2102
2103 shifted_vline = vector_init (vector_count(vline));
2104 /* use memcpy? */
2105 for (index = 1; index < vector_max (vline); index++)
2106 {
2107 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2108 }
2109
2110 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2111
2112 vector_free(shifted_vline);
2113 vty->node = onode;
2114 return ret;
2115 }
2116
2117
paul9ab68122003-01-18 01:16:20 +00002118 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002119
hasso87d683b2005-01-16 23:31:54 +00002120 if (vtysh)
2121 return saved_ret;
2122
paulb92938a2002-12-13 21:20:42 +00002123 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002124 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002125 && vty->node > CONFIG_NODE )
2126 {
paul9ab68122003-01-18 01:16:20 +00002127 try_node = node_parent(try_node);
2128 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002129 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002130 tried = 1;
2131 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002132 {
paul9ab68122003-01-18 01:16:20 +00002133 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002134 return ret;
2135 }
paulb92938a2002-12-13 21:20:42 +00002136 }
paul9ab68122003-01-18 01:16:20 +00002137 /* no command succeeded, reset the vty to the original node and
2138 return the error for this node */
2139 if ( tried )
2140 vty->node = onode;
2141 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002142}
2143
paul718e3742002-12-13 20:15:29 +00002144/* Execute command by argument readline. */
2145int
2146cmd_execute_command_strict (vector vline, struct vty *vty,
2147 struct cmd_element **cmd)
2148{
hasso8c328f12004-10-05 21:01:23 +00002149 unsigned int i;
2150 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002151 vector cmd_vector;
2152 struct cmd_element *cmd_element;
2153 struct cmd_element *matched_element;
2154 unsigned int matched_count, incomplete_count;
2155 int argc;
paul9035efa2004-10-10 11:56:56 +00002156 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002157 int varflag;
2158 enum match_type match = 0;
2159 char *command;
2160
2161 /* Make copy of command element */
2162 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2163
2164 for (index = 0; index < vector_max (vline); index++)
2165 {
2166 int ret;
2167
2168 command = vector_slot (vline, index);
2169
2170 match = cmd_filter_by_string (vector_slot (vline, index),
2171 cmd_vector, index);
2172
2173 /* If command meets '.VARARG' then finish matching. */
2174 if (match == vararg_match)
2175 break;
2176
2177 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2178 if (ret == 1)
2179 {
2180 vector_free (cmd_vector);
2181 return CMD_ERR_AMBIGUOUS;
2182 }
2183 if (ret == 2)
2184 {
2185 vector_free (cmd_vector);
2186 return CMD_ERR_NO_MATCH;
2187 }
2188 }
2189
2190 /* Check matched count. */
2191 matched_element = NULL;
2192 matched_count = 0;
2193 incomplete_count = 0;
2194 for (i = 0; i < vector_max (cmd_vector); i++)
2195 if (vector_slot (cmd_vector,i) != NULL)
2196 {
2197 cmd_element = vector_slot (cmd_vector,i);
2198
2199 if (match == vararg_match || index >= cmd_element->cmdsize)
2200 {
2201 matched_element = cmd_element;
2202 matched_count++;
2203 }
2204 else
2205 incomplete_count++;
2206 }
2207
2208 /* Finish of using cmd_vector. */
2209 vector_free (cmd_vector);
2210
2211 /* To execute command, matched_count must be 1.*/
2212 if (matched_count == 0)
2213 {
2214 if (incomplete_count)
2215 return CMD_ERR_INCOMPLETE;
2216 else
2217 return CMD_ERR_NO_MATCH;
2218 }
2219
2220 if (matched_count > 1)
2221 return CMD_ERR_AMBIGUOUS;
2222
2223 /* Argument treatment */
2224 varflag = 0;
2225 argc = 0;
2226
2227 for (i = 0; i < vector_max (vline); i++)
2228 {
2229 if (varflag)
2230 argv[argc++] = vector_slot (vline, i);
2231 else
2232 {
2233 vector descvec = vector_slot (matched_element->strvec, i);
2234
2235 if (vector_max (descvec) == 1)
2236 {
2237 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002238
hasso8c328f12004-10-05 21:01:23 +00002239 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002240 varflag = 1;
2241
hasso8c328f12004-10-05 21:01:23 +00002242 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002243 argv[argc++] = vector_slot (vline, i);
2244 }
2245 else
2246 argv[argc++] = vector_slot (vline, i);
2247 }
2248
2249 if (argc >= CMD_ARGC_MAX)
2250 return CMD_ERR_EXEED_ARGC_MAX;
2251 }
2252
2253 /* For vtysh execution. */
2254 if (cmd)
2255 *cmd = matched_element;
2256
2257 if (matched_element->daemon)
2258 return CMD_SUCCESS_DAEMON;
2259
2260 /* Now execute matched command */
2261 return (*matched_element->func) (matched_element, vty, argc, argv);
2262}
2263
2264/* Configration make from file. */
2265int
2266config_from_file (struct vty *vty, FILE *fp)
2267{
2268 int ret;
2269 vector vline;
2270
2271 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2272 {
2273 vline = cmd_make_strvec (vty->buf);
2274
2275 /* In case of comment line */
2276 if (vline == NULL)
2277 continue;
2278 /* Execute configuration command : this is strict match */
2279 ret = cmd_execute_command_strict (vline, vty, NULL);
2280
2281 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002282 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002283 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2284 {
paulb92938a2002-12-13 21:20:42 +00002285 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002286 ret = cmd_execute_command_strict (vline, vty, NULL);
2287 }
paul9ab68122003-01-18 01:16:20 +00002288
paul718e3742002-12-13 20:15:29 +00002289 cmd_free_strvec (vline);
2290
hassoddd85ed2004-10-13 08:18:07 +00002291 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2292 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002293 return ret;
2294 }
2295 return CMD_SUCCESS;
2296}
2297
2298/* Configration from terminal */
2299DEFUN (config_terminal,
2300 config_terminal_cmd,
2301 "configure terminal",
2302 "Configuration from vty interface\n"
2303 "Configuration terminal\n")
2304{
2305 if (vty_config_lock (vty))
2306 vty->node = CONFIG_NODE;
2307 else
2308 {
2309 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2310 return CMD_WARNING;
2311 }
2312 return CMD_SUCCESS;
2313}
2314
2315/* Enable command */
2316DEFUN (enable,
2317 config_enable_cmd,
2318 "enable",
2319 "Turn on privileged mode command\n")
2320{
2321 /* If enable password is NULL, change to ENABLE_NODE */
2322 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2323 vty->type == VTY_SHELL_SERV)
2324 vty->node = ENABLE_NODE;
2325 else
2326 vty->node = AUTH_ENABLE_NODE;
2327
2328 return CMD_SUCCESS;
2329}
2330
2331/* Disable command */
2332DEFUN (disable,
2333 config_disable_cmd,
2334 "disable",
2335 "Turn off privileged mode command\n")
2336{
2337 if (vty->node == ENABLE_NODE)
2338 vty->node = VIEW_NODE;
2339 return CMD_SUCCESS;
2340}
2341
2342/* Down vty node level. */
2343DEFUN (config_exit,
2344 config_exit_cmd,
2345 "exit",
2346 "Exit current mode and down to previous mode\n")
2347{
2348 switch (vty->node)
2349 {
2350 case VIEW_NODE:
2351 case ENABLE_NODE:
2352 if (vty_shell (vty))
2353 exit (0);
2354 else
2355 vty->status = VTY_CLOSE;
2356 break;
2357 case CONFIG_NODE:
2358 vty->node = ENABLE_NODE;
2359 vty_config_unlock (vty);
2360 break;
2361 case INTERFACE_NODE:
2362 case ZEBRA_NODE:
2363 case BGP_NODE:
2364 case RIP_NODE:
2365 case RIPNG_NODE:
2366 case OSPF_NODE:
2367 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002368 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002369 case KEYCHAIN_NODE:
2370 case MASC_NODE:
2371 case RMAP_NODE:
2372 case VTY_NODE:
2373 vty->node = CONFIG_NODE;
2374 break;
2375 case BGP_VPNV4_NODE:
2376 case BGP_IPV4_NODE:
2377 case BGP_IPV4M_NODE:
2378 case BGP_IPV6_NODE:
2379 vty->node = BGP_NODE;
2380 break;
2381 case KEYCHAIN_KEY_NODE:
2382 vty->node = KEYCHAIN_NODE;
2383 break;
2384 default:
2385 break;
2386 }
2387 return CMD_SUCCESS;
2388}
2389
2390/* quit is alias of exit. */
2391ALIAS (config_exit,
2392 config_quit_cmd,
2393 "quit",
2394 "Exit current mode and down to previous mode\n")
2395
2396/* End of configuration. */
2397DEFUN (config_end,
2398 config_end_cmd,
2399 "end",
2400 "End current mode and change to enable mode.")
2401{
2402 switch (vty->node)
2403 {
2404 case VIEW_NODE:
2405 case ENABLE_NODE:
2406 /* Nothing to do. */
2407 break;
2408 case CONFIG_NODE:
2409 case INTERFACE_NODE:
2410 case ZEBRA_NODE:
2411 case RIP_NODE:
2412 case RIPNG_NODE:
2413 case BGP_NODE:
2414 case BGP_VPNV4_NODE:
2415 case BGP_IPV4_NODE:
2416 case BGP_IPV4M_NODE:
2417 case BGP_IPV6_NODE:
2418 case RMAP_NODE:
2419 case OSPF_NODE:
2420 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002421 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002422 case KEYCHAIN_NODE:
2423 case KEYCHAIN_KEY_NODE:
2424 case MASC_NODE:
2425 case VTY_NODE:
2426 vty_config_unlock (vty);
2427 vty->node = ENABLE_NODE;
2428 break;
2429 default:
2430 break;
2431 }
2432 return CMD_SUCCESS;
2433}
2434
2435/* Show version. */
2436DEFUN (show_version,
2437 show_version_cmd,
2438 "show version",
2439 SHOW_STR
2440 "Displays zebra version\n")
2441{
hasso6590f2c2004-10-19 20:40:08 +00002442 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name, VTY_NEWLINE);
2443 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002444
2445 return CMD_SUCCESS;
2446}
2447
2448/* Help display function for all node. */
2449DEFUN (config_help,
2450 config_help_cmd,
2451 "help",
2452 "Description of the interactive help system\n")
2453{
2454 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002455 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002456anytime at the command line please press '?'.%s\
2457%s\
2458If nothing matches, the help list will be empty and you must backup%s\
2459 until entering a '?' shows the available options.%s\
2460Two styles of help are provided:%s\
24611. Full help is available when you are ready to enter a%s\
2462command argument (e.g. 'show ?') and describes each possible%s\
2463argument.%s\
24642. Partial help is provided when an abbreviated argument is entered%s\
2465 and you want to know what arguments match the input%s\
2466 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2467 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2468 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2469 return CMD_SUCCESS;
2470}
2471
2472/* Help display function for all node. */
2473DEFUN (config_list,
2474 config_list_cmd,
2475 "list",
2476 "Print command list\n")
2477{
hasso8c328f12004-10-05 21:01:23 +00002478 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002479 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2480 struct cmd_element *cmd;
2481
2482 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2483 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2484 vty_out (vty, " %s%s", cmd->string,
2485 VTY_NEWLINE);
2486 return CMD_SUCCESS;
2487}
2488
2489/* Write current configuration into file. */
2490DEFUN (config_write_file,
2491 config_write_file_cmd,
2492 "write file",
2493 "Write running configuration to memory, network, or terminal\n"
2494 "Write to configuration file\n")
2495{
hasso8c328f12004-10-05 21:01:23 +00002496 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002497 int fd;
2498 struct cmd_node *node;
2499 char *config_file;
2500 char *config_file_tmp = NULL;
2501 char *config_file_sav = NULL;
2502 struct vty *file_vty;
2503
2504 /* Check and see if we are operating under vtysh configuration */
2505 if (host.config == NULL)
2506 {
2507 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2508 VTY_NEWLINE);
2509 return CMD_WARNING;
2510 }
2511
2512 /* Get filename. */
2513 config_file = host.config;
2514
2515 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2516 strcpy (config_file_sav, config_file);
2517 strcat (config_file_sav, CONF_BACKUP_EXT);
2518
2519
2520 config_file_tmp = malloc (strlen (config_file) + 8);
2521 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2522
2523 /* Open file to configuration write. */
2524 fd = mkstemp (config_file_tmp);
2525 if (fd < 0)
2526 {
2527 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2528 VTY_NEWLINE);
2529 free (config_file_tmp);
2530 free (config_file_sav);
2531 return CMD_WARNING;
2532 }
2533
2534 /* Make vty for configuration file. */
2535 file_vty = vty_new ();
2536 file_vty->fd = fd;
2537 file_vty->type = VTY_FILE;
2538
2539 /* Config file header print. */
2540 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2541 vty_time_print (file_vty, 1);
2542 vty_out (file_vty, "!\n");
2543
2544 for (i = 0; i < vector_max (cmdvec); i++)
2545 if ((node = vector_slot (cmdvec, i)) && node->func)
2546 {
2547 if ((*node->func) (file_vty))
2548 vty_out (file_vty, "!\n");
2549 }
2550 vty_close (file_vty);
2551
2552 if (unlink (config_file_sav) != 0)
2553 if (errno != ENOENT)
2554 {
2555 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2556 VTY_NEWLINE);
2557 free (config_file_sav);
2558 free (config_file_tmp);
2559 unlink (config_file_tmp);
2560 return CMD_WARNING;
2561 }
2562 if (link (config_file, config_file_sav) != 0)
2563 {
2564 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2565 VTY_NEWLINE);
2566 free (config_file_sav);
2567 free (config_file_tmp);
2568 unlink (config_file_tmp);
2569 return CMD_WARNING;
2570 }
2571 sync ();
2572 if (unlink (config_file) != 0)
2573 {
2574 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2575 VTY_NEWLINE);
2576 free (config_file_sav);
2577 free (config_file_tmp);
2578 unlink (config_file_tmp);
2579 return CMD_WARNING;
2580 }
2581 if (link (config_file_tmp, config_file) != 0)
2582 {
2583 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2584 VTY_NEWLINE);
2585 free (config_file_sav);
2586 free (config_file_tmp);
2587 unlink (config_file_tmp);
2588 return CMD_WARNING;
2589 }
2590 unlink (config_file_tmp);
2591 sync ();
2592
2593 free (config_file_sav);
2594 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002595
2596 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2597 {
2598 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002599 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002600 return CMD_WARNING;
2601 }
2602
paul718e3742002-12-13 20:15:29 +00002603 vty_out (vty, "Configuration saved to %s%s", config_file,
2604 VTY_NEWLINE);
2605 return CMD_SUCCESS;
2606}
2607
2608ALIAS (config_write_file,
2609 config_write_cmd,
2610 "write",
2611 "Write running configuration to memory, network, or terminal\n")
2612
2613ALIAS (config_write_file,
2614 config_write_memory_cmd,
2615 "write memory",
2616 "Write running configuration to memory, network, or terminal\n"
2617 "Write configuration to the file (same as write file)\n")
2618
2619ALIAS (config_write_file,
2620 copy_runningconfig_startupconfig_cmd,
2621 "copy running-config startup-config",
2622 "Copy configuration\n"
2623 "Copy running config to... \n"
2624 "Copy running config to startup config (same as write file)\n")
2625
2626/* Write current configuration into the terminal. */
2627DEFUN (config_write_terminal,
2628 config_write_terminal_cmd,
2629 "write terminal",
2630 "Write running configuration to memory, network, or terminal\n"
2631 "Write to terminal\n")
2632{
hasso8c328f12004-10-05 21:01:23 +00002633 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002634 struct cmd_node *node;
2635
2636 if (vty->type == VTY_SHELL_SERV)
2637 {
2638 for (i = 0; i < vector_max (cmdvec); i++)
2639 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2640 {
2641 if ((*node->func) (vty))
2642 vty_out (vty, "!%s", VTY_NEWLINE);
2643 }
2644 }
2645 else
2646 {
2647 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2648 VTY_NEWLINE);
2649 vty_out (vty, "!%s", VTY_NEWLINE);
2650
2651 for (i = 0; i < vector_max (cmdvec); i++)
2652 if ((node = vector_slot (cmdvec, i)) && node->func)
2653 {
2654 if ((*node->func) (vty))
2655 vty_out (vty, "!%s", VTY_NEWLINE);
2656 }
2657 vty_out (vty, "end%s",VTY_NEWLINE);
2658 }
2659 return CMD_SUCCESS;
2660}
2661
2662/* Write current configuration into the terminal. */
2663ALIAS (config_write_terminal,
2664 show_running_config_cmd,
2665 "show running-config",
2666 SHOW_STR
2667 "running configuration\n")
2668
2669/* Write startup configuration into the terminal. */
2670DEFUN (show_startup_config,
2671 show_startup_config_cmd,
2672 "show startup-config",
2673 SHOW_STR
2674 "Contentes of startup configuration\n")
2675{
2676 char buf[BUFSIZ];
2677 FILE *confp;
2678
2679 confp = fopen (host.config, "r");
2680 if (confp == NULL)
2681 {
2682 vty_out (vty, "Can't open configuration file [%s]%s",
2683 host.config, VTY_NEWLINE);
2684 return CMD_WARNING;
2685 }
2686
2687 while (fgets (buf, BUFSIZ, confp))
2688 {
2689 char *cp = buf;
2690
2691 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2692 cp++;
2693 *cp = '\0';
2694
2695 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2696 }
2697
2698 fclose (confp);
2699
2700 return CMD_SUCCESS;
2701}
2702
2703/* Hostname configuration */
2704DEFUN (config_hostname,
2705 hostname_cmd,
2706 "hostname WORD",
2707 "Set system's network name\n"
2708 "This system's network name\n")
2709{
2710 if (!isalpha((int) *argv[0]))
2711 {
2712 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2713 return CMD_WARNING;
2714 }
2715
2716 if (host.name)
2717 XFREE (0, host.name);
2718
2719 host.name = strdup (argv[0]);
2720 return CMD_SUCCESS;
2721}
2722
2723DEFUN (config_no_hostname,
2724 no_hostname_cmd,
2725 "no hostname [HOSTNAME]",
2726 NO_STR
2727 "Reset system's network name\n"
2728 "Host name of this router\n")
2729{
2730 if (host.name)
2731 XFREE (0, host.name);
2732 host.name = NULL;
2733 return CMD_SUCCESS;
2734}
2735
2736/* VTY interface password set. */
2737DEFUN (config_password, password_cmd,
2738 "password (8|) WORD",
2739 "Assign the terminal connection password\n"
2740 "Specifies a HIDDEN password will follow\n"
2741 "dummy string \n"
2742 "The HIDDEN line password string\n")
2743{
2744 /* Argument check. */
2745 if (argc == 0)
2746 {
2747 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2748 return CMD_WARNING;
2749 }
2750
2751 if (argc == 2)
2752 {
2753 if (*argv[0] == '8')
2754 {
2755 if (host.password)
2756 XFREE (0, host.password);
2757 host.password = NULL;
2758 if (host.password_encrypt)
2759 XFREE (0, host.password_encrypt);
2760 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2761 return CMD_SUCCESS;
2762 }
2763 else
2764 {
2765 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2766 return CMD_WARNING;
2767 }
2768 }
2769
2770 if (!isalnum ((int) *argv[0]))
2771 {
2772 vty_out (vty,
2773 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2774 return CMD_WARNING;
2775 }
2776
2777 if (host.password)
2778 XFREE (0, host.password);
2779 host.password = NULL;
2780
2781 if (host.encrypt)
2782 {
2783 if (host.password_encrypt)
2784 XFREE (0, host.password_encrypt);
2785 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2786 }
2787 else
2788 host.password = XSTRDUP (0, argv[0]);
2789
2790 return CMD_SUCCESS;
2791}
2792
2793ALIAS (config_password, password_text_cmd,
2794 "password LINE",
2795 "Assign the terminal connection password\n"
2796 "The UNENCRYPTED (cleartext) line password\n")
2797
2798/* VTY enable password set. */
2799DEFUN (config_enable_password, enable_password_cmd,
2800 "enable password (8|) WORD",
2801 "Modify enable password parameters\n"
2802 "Assign the privileged level password\n"
2803 "Specifies a HIDDEN password will follow\n"
2804 "dummy string \n"
2805 "The HIDDEN 'enable' password string\n")
2806{
2807 /* Argument check. */
2808 if (argc == 0)
2809 {
2810 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2811 return CMD_WARNING;
2812 }
2813
2814 /* Crypt type is specified. */
2815 if (argc == 2)
2816 {
2817 if (*argv[0] == '8')
2818 {
2819 if (host.enable)
2820 XFREE (0, host.enable);
2821 host.enable = NULL;
2822
2823 if (host.enable_encrypt)
2824 XFREE (0, host.enable_encrypt);
2825 host.enable_encrypt = XSTRDUP (0, argv[1]);
2826
2827 return CMD_SUCCESS;
2828 }
2829 else
2830 {
2831 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2832 return CMD_WARNING;
2833 }
2834 }
2835
2836 if (!isalnum ((int) *argv[0]))
2837 {
2838 vty_out (vty,
2839 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2840 return CMD_WARNING;
2841 }
2842
2843 if (host.enable)
2844 XFREE (0, host.enable);
2845 host.enable = NULL;
2846
2847 /* Plain password input. */
2848 if (host.encrypt)
2849 {
2850 if (host.enable_encrypt)
2851 XFREE (0, host.enable_encrypt);
2852 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2853 }
2854 else
2855 host.enable = XSTRDUP (0, argv[0]);
2856
2857 return CMD_SUCCESS;
2858}
2859
2860ALIAS (config_enable_password,
2861 enable_password_text_cmd,
2862 "enable password LINE",
2863 "Modify enable password parameters\n"
2864 "Assign the privileged level password\n"
2865 "The UNENCRYPTED (cleartext) 'enable' password\n")
2866
2867/* VTY enable password delete. */
2868DEFUN (no_config_enable_password, no_enable_password_cmd,
2869 "no enable password",
2870 NO_STR
2871 "Modify enable password parameters\n"
2872 "Assign the privileged level password\n")
2873{
2874 if (host.enable)
2875 XFREE (0, host.enable);
2876 host.enable = NULL;
2877
2878 if (host.enable_encrypt)
2879 XFREE (0, host.enable_encrypt);
2880 host.enable_encrypt = NULL;
2881
2882 return CMD_SUCCESS;
2883}
2884
2885DEFUN (service_password_encrypt,
2886 service_password_encrypt_cmd,
2887 "service password-encryption",
2888 "Set up miscellaneous service\n"
2889 "Enable encrypted passwords\n")
2890{
2891 if (host.encrypt)
2892 return CMD_SUCCESS;
2893
2894 host.encrypt = 1;
2895
2896 if (host.password)
2897 {
2898 if (host.password_encrypt)
2899 XFREE (0, host.password_encrypt);
2900 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2901 }
2902 if (host.enable)
2903 {
2904 if (host.enable_encrypt)
2905 XFREE (0, host.enable_encrypt);
2906 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2907 }
2908
2909 return CMD_SUCCESS;
2910}
2911
2912DEFUN (no_service_password_encrypt,
2913 no_service_password_encrypt_cmd,
2914 "no service password-encryption",
2915 NO_STR
2916 "Set up miscellaneous service\n"
2917 "Enable encrypted passwords\n")
2918{
2919 if (! host.encrypt)
2920 return CMD_SUCCESS;
2921
2922 host.encrypt = 0;
2923
2924 if (host.password_encrypt)
2925 XFREE (0, host.password_encrypt);
2926 host.password_encrypt = NULL;
2927
2928 if (host.enable_encrypt)
2929 XFREE (0, host.enable_encrypt);
2930 host.enable_encrypt = NULL;
2931
2932 return CMD_SUCCESS;
2933}
2934
2935DEFUN (config_terminal_length, config_terminal_length_cmd,
2936 "terminal length <0-512>",
2937 "Set terminal line parameters\n"
2938 "Set number of lines on a screen\n"
2939 "Number of lines on screen (0 for no pausing)\n")
2940{
2941 int lines;
2942 char *endptr = NULL;
2943
2944 lines = strtol (argv[0], &endptr, 10);
2945 if (lines < 0 || lines > 512 || *endptr != '\0')
2946 {
2947 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2948 return CMD_WARNING;
2949 }
2950 vty->lines = lines;
2951
2952 return CMD_SUCCESS;
2953}
2954
2955DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2956 "terminal no length",
2957 "Set terminal line parameters\n"
2958 NO_STR
2959 "Set number of lines on a screen\n")
2960{
2961 vty->lines = -1;
2962 return CMD_SUCCESS;
2963}
2964
2965DEFUN (service_terminal_length, service_terminal_length_cmd,
2966 "service terminal-length <0-512>",
2967 "Set up miscellaneous service\n"
2968 "System wide terminal length configuration\n"
2969 "Number of lines of VTY (0 means no line control)\n")
2970{
2971 int lines;
2972 char *endptr = NULL;
2973
2974 lines = strtol (argv[0], &endptr, 10);
2975 if (lines < 0 || lines > 512 || *endptr != '\0')
2976 {
2977 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2978 return CMD_WARNING;
2979 }
2980 host.lines = lines;
2981
2982 return CMD_SUCCESS;
2983}
2984
2985DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2986 "no service terminal-length [<0-512>]",
2987 NO_STR
2988 "Set up miscellaneous service\n"
2989 "System wide terminal length configuration\n"
2990 "Number of lines of VTY (0 means no line control)\n")
2991{
2992 host.lines = -1;
2993 return CMD_SUCCESS;
2994}
2995
ajs2885f722004-12-17 23:16:33 +00002996DEFUN_HIDDEN (do_echo,
2997 echo_cmd,
2998 "echo .MESSAGE",
2999 "Echo a message back to the vty\n"
3000 "The message to echo\n")
3001{
3002 char *message;
3003
ajsf6834d42005-01-28 20:28:35 +00003004 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3005 VTY_NEWLINE);
3006 if (message)
3007 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003008 return CMD_SUCCESS;
3009}
3010
ajs274a4a42004-12-07 15:39:31 +00003011DEFUN (config_logmsg,
3012 config_logmsg_cmd,
3013 "logmsg "LOG_LEVELS" .MESSAGE",
3014 "Send a message to enabled logging destinations\n"
3015 LOG_LEVEL_DESC
3016 "The message to send\n")
3017{
3018 int level;
3019 char *message;
3020
3021 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3022 return CMD_ERR_NO_MATCH;
3023
ajsf6834d42005-01-28 20:28:35 +00003024 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3025 if (message)
3026 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003027 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}