blob: 7656f68061a50e1d027a4e29db9e7bede0d7b432 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paulb45da6f2005-03-08 15:16:57 +00002 $Id: command.c,v 1.39 2005/03/08 15:16:57 paul 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
paul3b0c5d92005-03-08 10:43:43 +0000600 if (host.motdfile)
601 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
602 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000603 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
604
605 return 1;
606}
607
608/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000609static vector
paul718e3742002-12-13 20:15:29 +0000610cmd_node_vector (vector v, enum node_type ntype)
611{
612 struct cmd_node *cnode = vector_slot (v, ntype);
613 return cnode->cmd_vector;
614}
615
ajs274a4a42004-12-07 15:39:31 +0000616#if 0
617/* Filter command vector by symbol. This function is not actually used;
618 * should it be deleted? */
619static int
paul718e3742002-12-13 20:15:29 +0000620cmd_filter_by_symbol (char *command, char *symbol)
621{
622 int i, lim;
623
624 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
625 {
626 i = 0;
627 lim = strlen (command);
628 while (i < lim)
629 {
630 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
631 return 1;
632 i++;
633 }
634 return 0;
635 }
636 if (strcmp (symbol, "STRING") == 0)
637 {
638 i = 0;
639 lim = strlen (command);
640 while (i < lim)
641 {
642 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
643 return 1;
644 i++;
645 }
646 return 0;
647 }
648 if (strcmp (symbol, "IFNAME") == 0)
649 {
650 i = 0;
651 lim = strlen (command);
652 while (i < lim)
653 {
654 if (! isalnum ((int) command[i]))
655 return 1;
656 i++;
657 }
658 return 0;
659 }
660 return 0;
661}
ajs274a4a42004-12-07 15:39:31 +0000662#endif
paul718e3742002-12-13 20:15:29 +0000663
664/* Completion match types. */
665enum match_type
666{
667 no_match,
668 extend_match,
669 ipv4_prefix_match,
670 ipv4_match,
671 ipv6_prefix_match,
672 ipv6_match,
673 range_match,
674 vararg_match,
675 partly_match,
676 exact_match
677};
678
ajs274a4a42004-12-07 15:39:31 +0000679static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000680cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000681{
hasso8c328f12004-10-05 21:01:23 +0000682 const char *sp;
paul718e3742002-12-13 20:15:29 +0000683 int dots = 0, nums = 0;
684 char buf[4];
685
686 if (str == NULL)
687 return partly_match;
688
689 for (;;)
690 {
691 memset (buf, 0, sizeof (buf));
692 sp = str;
693 while (*str != '\0')
694 {
695 if (*str == '.')
696 {
697 if (dots >= 3)
698 return no_match;
699
700 if (*(str + 1) == '.')
701 return no_match;
702
703 if (*(str + 1) == '\0')
704 return partly_match;
705
706 dots++;
707 break;
708 }
709 if (!isdigit ((int) *str))
710 return no_match;
711
712 str++;
713 }
714
715 if (str - sp > 3)
716 return no_match;
717
718 strncpy (buf, sp, str - sp);
719 if (atoi (buf) > 255)
720 return no_match;
721
722 nums++;
723
724 if (*str == '\0')
725 break;
726
727 str++;
728 }
729
730 if (nums < 4)
731 return partly_match;
732
733 return exact_match;
734}
735
ajs274a4a42004-12-07 15:39:31 +0000736static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000737cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000738{
hasso8c328f12004-10-05 21:01:23 +0000739 const char *sp;
paul718e3742002-12-13 20:15:29 +0000740 int dots = 0;
741 char buf[4];
742
743 if (str == NULL)
744 return partly_match;
745
746 for (;;)
747 {
748 memset (buf, 0, sizeof (buf));
749 sp = str;
750 while (*str != '\0' && *str != '/')
751 {
752 if (*str == '.')
753 {
754 if (dots == 3)
755 return no_match;
756
757 if (*(str + 1) == '.' || *(str + 1) == '/')
758 return no_match;
759
760 if (*(str + 1) == '\0')
761 return partly_match;
762
763 dots++;
764 break;
765 }
766
767 if (!isdigit ((int) *str))
768 return no_match;
769
770 str++;
771 }
772
773 if (str - sp > 3)
774 return no_match;
775
776 strncpy (buf, sp, str - sp);
777 if (atoi (buf) > 255)
778 return no_match;
779
780 if (dots == 3)
781 {
782 if (*str == '/')
783 {
784 if (*(str + 1) == '\0')
785 return partly_match;
786
787 str++;
788 break;
789 }
790 else if (*str == '\0')
791 return partly_match;
792 }
793
794 if (*str == '\0')
795 return partly_match;
796
797 str++;
798 }
799
800 sp = str;
801 while (*str != '\0')
802 {
803 if (!isdigit ((int) *str))
804 return no_match;
805
806 str++;
807 }
808
809 if (atoi (sp) > 32)
810 return no_match;
811
812 return exact_match;
813}
814
815#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
816#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
817#define STATE_START 1
818#define STATE_COLON 2
819#define STATE_DOUBLE 3
820#define STATE_ADDR 4
821#define STATE_DOT 5
822#define STATE_SLASH 6
823#define STATE_MASK 7
824
paul22e0a9e2003-07-11 17:55:46 +0000825#ifdef HAVE_IPV6
826
ajs274a4a42004-12-07 15:39:31 +0000827static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000828cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000829{
830 int state = STATE_START;
831 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000832 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000833 struct sockaddr_in6 sin6_dummy;
834 int ret;
paul718e3742002-12-13 20:15:29 +0000835
836 if (str == NULL)
837 return partly_match;
838
839 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
840 return no_match;
841
hasso726f9b22003-05-25 21:04:54 +0000842 /* use inet_pton that has a better support,
843 * for example inet_pton can support the automatic addresses:
844 * ::1.2.3.4
845 */
846 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
847
848 if (ret == 1)
849 return exact_match;
850
paul718e3742002-12-13 20:15:29 +0000851 while (*str != '\0')
852 {
853 switch (state)
854 {
855 case STATE_START:
856 if (*str == ':')
857 {
858 if (*(str + 1) != ':' && *(str + 1) != '\0')
859 return no_match;
860 colons--;
861 state = STATE_COLON;
862 }
863 else
864 {
865 sp = str;
866 state = STATE_ADDR;
867 }
868
869 continue;
870 case STATE_COLON:
871 colons++;
872 if (*(str + 1) == ':')
873 state = STATE_DOUBLE;
874 else
875 {
876 sp = str + 1;
877 state = STATE_ADDR;
878 }
879 break;
880 case STATE_DOUBLE:
881 if (double_colon)
882 return no_match;
883
884 if (*(str + 1) == ':')
885 return no_match;
886 else
887 {
888 if (*(str + 1) != '\0')
889 colons++;
890 sp = str + 1;
891 state = STATE_ADDR;
892 }
893
894 double_colon++;
895 nums++;
896 break;
897 case STATE_ADDR:
898 if (*(str + 1) == ':' || *(str + 1) == '\0')
899 {
900 if (str - sp > 3)
901 return no_match;
902
903 nums++;
904 state = STATE_COLON;
905 }
906 if (*(str + 1) == '.')
907 state = STATE_DOT;
908 break;
909 case STATE_DOT:
910 state = STATE_ADDR;
911 break;
912 default:
913 break;
914 }
915
916 if (nums > 8)
917 return no_match;
918
919 if (colons > 7)
920 return no_match;
921
922 str++;
923 }
924
925#if 0
926 if (nums < 11)
927 return partly_match;
928#endif /* 0 */
929
930 return exact_match;
931}
932
ajs274a4a42004-12-07 15:39:31 +0000933static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000934cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000935{
936 int state = STATE_START;
937 int colons = 0, nums = 0, double_colon = 0;
938 int mask;
hasso8c328f12004-10-05 21:01:23 +0000939 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000940 char *endptr = NULL;
941
942 if (str == NULL)
943 return partly_match;
944
945 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
946 return no_match;
947
948 while (*str != '\0' && state != STATE_MASK)
949 {
950 switch (state)
951 {
952 case STATE_START:
953 if (*str == ':')
954 {
955 if (*(str + 1) != ':' && *(str + 1) != '\0')
956 return no_match;
957 colons--;
958 state = STATE_COLON;
959 }
960 else
961 {
962 sp = str;
963 state = STATE_ADDR;
964 }
965
966 continue;
967 case STATE_COLON:
968 colons++;
969 if (*(str + 1) == '/')
970 return no_match;
971 else if (*(str + 1) == ':')
972 state = STATE_DOUBLE;
973 else
974 {
975 sp = str + 1;
976 state = STATE_ADDR;
977 }
978 break;
979 case STATE_DOUBLE:
980 if (double_colon)
981 return no_match;
982
983 if (*(str + 1) == ':')
984 return no_match;
985 else
986 {
987 if (*(str + 1) != '\0' && *(str + 1) != '/')
988 colons++;
989 sp = str + 1;
990
991 if (*(str + 1) == '/')
992 state = STATE_SLASH;
993 else
994 state = STATE_ADDR;
995 }
996
997 double_colon++;
998 nums += 1;
999 break;
1000 case STATE_ADDR:
1001 if (*(str + 1) == ':' || *(str + 1) == '.'
1002 || *(str + 1) == '\0' || *(str + 1) == '/')
1003 {
1004 if (str - sp > 3)
1005 return no_match;
1006
1007 for (; sp <= str; sp++)
1008 if (*sp == '/')
1009 return no_match;
1010
1011 nums++;
1012
1013 if (*(str + 1) == ':')
1014 state = STATE_COLON;
1015 else if (*(str + 1) == '.')
1016 state = STATE_DOT;
1017 else if (*(str + 1) == '/')
1018 state = STATE_SLASH;
1019 }
1020 break;
1021 case STATE_DOT:
1022 state = STATE_ADDR;
1023 break;
1024 case STATE_SLASH:
1025 if (*(str + 1) == '\0')
1026 return partly_match;
1027
1028 state = STATE_MASK;
1029 break;
1030 default:
1031 break;
1032 }
1033
1034 if (nums > 11)
1035 return no_match;
1036
1037 if (colons > 7)
1038 return no_match;
1039
1040 str++;
1041 }
1042
1043 if (state < STATE_MASK)
1044 return partly_match;
1045
1046 mask = strtol (str, &endptr, 10);
1047 if (*endptr != '\0')
1048 return no_match;
1049
1050 if (mask < 0 || mask > 128)
1051 return no_match;
1052
1053/* I don't know why mask < 13 makes command match partly.
1054 Forgive me to make this comments. I Want to set static default route
1055 because of lack of function to originate default in ospf6d; sorry
1056 yasu
1057 if (mask < 13)
1058 return partly_match;
1059*/
1060
1061 return exact_match;
1062}
1063
paul22e0a9e2003-07-11 17:55:46 +00001064#endif /* HAVE_IPV6 */
1065
paul718e3742002-12-13 20:15:29 +00001066#define DECIMAL_STRLEN_MAX 10
1067
ajs274a4a42004-12-07 15:39:31 +00001068static int
hasso8c328f12004-10-05 21:01:23 +00001069cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001070{
1071 char *p;
1072 char buf[DECIMAL_STRLEN_MAX + 1];
1073 char *endptr = NULL;
1074 unsigned long min, max, val;
1075
1076 if (str == NULL)
1077 return 1;
1078
1079 val = strtoul (str, &endptr, 10);
1080 if (*endptr != '\0')
1081 return 0;
1082
1083 range++;
1084 p = strchr (range, '-');
1085 if (p == NULL)
1086 return 0;
1087 if (p - range > DECIMAL_STRLEN_MAX)
1088 return 0;
1089 strncpy (buf, range, p - range);
1090 buf[p - range] = '\0';
1091 min = strtoul (buf, &endptr, 10);
1092 if (*endptr != '\0')
1093 return 0;
1094
1095 range = p + 1;
1096 p = strchr (range, '>');
1097 if (p == NULL)
1098 return 0;
1099 if (p - range > DECIMAL_STRLEN_MAX)
1100 return 0;
1101 strncpy (buf, range, p - range);
1102 buf[p - range] = '\0';
1103 max = strtoul (buf, &endptr, 10);
1104 if (*endptr != '\0')
1105 return 0;
1106
1107 if (val < min || val > max)
1108 return 0;
1109
1110 return 1;
1111}
1112
1113/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001114static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001115cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001116{
hasso8c328f12004-10-05 21:01:23 +00001117 unsigned int i;
1118 const char *str;
paul718e3742002-12-13 20:15:29 +00001119 struct cmd_element *cmd_element;
1120 enum match_type match_type;
1121 vector descvec;
1122 struct desc *desc;
1123
1124 match_type = no_match;
1125
1126 /* If command and cmd_element string does not match set NULL to vector */
1127 for (i = 0; i < vector_max (v); i++)
1128 if ((cmd_element = vector_slot (v, i)) != NULL)
1129 {
1130 if (index >= vector_max (cmd_element->strvec))
1131 vector_slot (v, i) = NULL;
1132 else
1133 {
hasso8c328f12004-10-05 21:01:23 +00001134 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001135 int matched = 0;
1136
1137 descvec = vector_slot (cmd_element->strvec, index);
1138
1139 for (j = 0; j < vector_max (descvec); j++)
1140 {
1141 desc = vector_slot (descvec, j);
1142 str = desc->cmd;
1143
1144 if (CMD_VARARG (str))
1145 {
1146 if (match_type < vararg_match)
1147 match_type = vararg_match;
1148 matched++;
1149 }
1150 else if (CMD_RANGE (str))
1151 {
1152 if (cmd_range_match (str, command))
1153 {
1154 if (match_type < range_match)
1155 match_type = range_match;
1156
1157 matched++;
1158 }
1159 }
paul22e0a9e2003-07-11 17:55:46 +00001160#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001161 else if (CMD_IPV6 (str))
1162 {
1163 if (cmd_ipv6_match (command))
1164 {
1165 if (match_type < ipv6_match)
1166 match_type = ipv6_match;
1167
1168 matched++;
1169 }
1170 }
1171 else if (CMD_IPV6_PREFIX (str))
1172 {
1173 if (cmd_ipv6_prefix_match (command))
1174 {
1175 if (match_type < ipv6_prefix_match)
1176 match_type = ipv6_prefix_match;
1177
1178 matched++;
1179 }
1180 }
paul22e0a9e2003-07-11 17:55:46 +00001181#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001182 else if (CMD_IPV4 (str))
1183 {
1184 if (cmd_ipv4_match (command))
1185 {
1186 if (match_type < ipv4_match)
1187 match_type = ipv4_match;
1188
1189 matched++;
1190 }
1191 }
1192 else if (CMD_IPV4_PREFIX (str))
1193 {
1194 if (cmd_ipv4_prefix_match (command))
1195 {
1196 if (match_type < ipv4_prefix_match)
1197 match_type = ipv4_prefix_match;
1198 matched++;
1199 }
1200 }
1201 else
1202 /* Check is this point's argument optional ? */
1203 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1204 {
1205 if (match_type < extend_match)
1206 match_type = extend_match;
1207 matched++;
1208 }
1209 else if (strncmp (command, str, strlen (command)) == 0)
1210 {
1211 if (strcmp (command, str) == 0)
1212 match_type = exact_match;
1213 else
1214 {
1215 if (match_type < partly_match)
1216 match_type = partly_match;
1217 }
1218 matched++;
1219 }
1220 }
1221 if (! matched)
1222 vector_slot (v, i) = NULL;
1223 }
1224 }
1225 return match_type;
1226}
1227
1228/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001229static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001230cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001231{
hasso8c328f12004-10-05 21:01:23 +00001232 unsigned int i;
1233 const char *str;
paul718e3742002-12-13 20:15:29 +00001234 struct cmd_element *cmd_element;
1235 enum match_type match_type;
1236 vector descvec;
1237 struct desc *desc;
1238
1239 match_type = no_match;
1240
1241 /* If command and cmd_element string does not match set NULL to vector */
1242 for (i = 0; i < vector_max (v); i++)
1243 if ((cmd_element = vector_slot (v, i)) != NULL)
1244 {
1245 /* If given index is bigger than max string vector of command,
1246 set NULL*/
1247 if (index >= vector_max (cmd_element->strvec))
1248 vector_slot (v, i) = NULL;
1249 else
1250 {
hasso8c328f12004-10-05 21:01:23 +00001251 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001252 int matched = 0;
1253
1254 descvec = vector_slot (cmd_element->strvec, index);
1255
1256 for (j = 0; j < vector_max (descvec); j++)
1257 {
1258 desc = vector_slot (descvec, j);
1259 str = desc->cmd;
1260
1261 if (CMD_VARARG (str))
1262 {
1263 if (match_type < vararg_match)
1264 match_type = vararg_match;
1265 matched++;
1266 }
1267 else if (CMD_RANGE (str))
1268 {
1269 if (cmd_range_match (str, command))
1270 {
1271 if (match_type < range_match)
1272 match_type = range_match;
1273 matched++;
1274 }
1275 }
paul22e0a9e2003-07-11 17:55:46 +00001276#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001277 else if (CMD_IPV6 (str))
1278 {
1279 if (cmd_ipv6_match (command) == exact_match)
1280 {
1281 if (match_type < ipv6_match)
1282 match_type = ipv6_match;
1283 matched++;
1284 }
1285 }
1286 else if (CMD_IPV6_PREFIX (str))
1287 {
1288 if (cmd_ipv6_prefix_match (command) == exact_match)
1289 {
1290 if (match_type < ipv6_prefix_match)
1291 match_type = ipv6_prefix_match;
1292 matched++;
1293 }
1294 }
paul22e0a9e2003-07-11 17:55:46 +00001295#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001296 else if (CMD_IPV4 (str))
1297 {
1298 if (cmd_ipv4_match (command) == exact_match)
1299 {
1300 if (match_type < ipv4_match)
1301 match_type = ipv4_match;
1302 matched++;
1303 }
1304 }
1305 else if (CMD_IPV4_PREFIX (str))
1306 {
1307 if (cmd_ipv4_prefix_match (command) == exact_match)
1308 {
1309 if (match_type < ipv4_prefix_match)
1310 match_type = ipv4_prefix_match;
1311 matched++;
1312 }
1313 }
1314 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1315 {
1316 if (match_type < extend_match)
1317 match_type = extend_match;
1318 matched++;
1319 }
1320 else
1321 {
1322 if (strcmp (command, str) == 0)
1323 {
1324 match_type = exact_match;
1325 matched++;
1326 }
1327 }
1328 }
1329 if (! matched)
1330 vector_slot (v, i) = NULL;
1331 }
1332 }
1333 return match_type;
1334}
1335
1336/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001337static int
paul718e3742002-12-13 20:15:29 +00001338is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1339{
hasso8c328f12004-10-05 21:01:23 +00001340 unsigned int i;
1341 unsigned int j;
1342 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001343 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001344 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001345 vector descvec;
1346 struct desc *desc;
1347
1348 for (i = 0; i < vector_max (v); i++)
1349 if ((cmd_element = vector_slot (v, i)) != NULL)
1350 {
1351 int match = 0;
1352
1353 descvec = vector_slot (cmd_element->strvec, index);
1354
1355 for (j = 0; j < vector_max (descvec); j++)
1356 {
1357 enum match_type ret;
1358
1359 desc = vector_slot (descvec, j);
1360 str = desc->cmd;
1361
1362 switch (type)
1363 {
1364 case exact_match:
1365 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1366 && strcmp (command, str) == 0)
1367 match++;
1368 break;
1369 case partly_match:
1370 if (! (CMD_OPTION (str) || CMD_VARIABLE (str))
1371 && strncmp (command, str, strlen (command)) == 0)
1372 {
1373 if (matched && strcmp (matched, str) != 0)
1374 return 1; /* There is ambiguous match. */
1375 else
1376 matched = str;
1377 match++;
1378 }
1379 break;
1380 case range_match:
1381 if (cmd_range_match (str, command))
1382 {
1383 if (matched && strcmp (matched, str) != 0)
1384 return 1;
1385 else
1386 matched = str;
1387 match++;
1388 }
1389 break;
paul22e0a9e2003-07-11 17:55:46 +00001390#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001391 case ipv6_match:
1392 if (CMD_IPV6 (str))
1393 match++;
1394 break;
1395 case ipv6_prefix_match:
1396 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1397 {
1398 if (ret == partly_match)
1399 return 2; /* There is incomplete match. */
1400
1401 match++;
1402 }
1403 break;
paul22e0a9e2003-07-11 17:55:46 +00001404#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001405 case ipv4_match:
1406 if (CMD_IPV4 (str))
1407 match++;
1408 break;
1409 case ipv4_prefix_match:
1410 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1411 {
1412 if (ret == partly_match)
1413 return 2; /* There is incomplete match. */
1414
1415 match++;
1416 }
1417 break;
1418 case extend_match:
1419 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1420 match++;
1421 break;
1422 case no_match:
1423 default:
1424 break;
1425 }
1426 }
1427 if (! match)
1428 vector_slot (v, i) = NULL;
1429 }
1430 return 0;
1431}
1432
1433/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001434static const char *
hasso8c328f12004-10-05 21:01:23 +00001435cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001436{
1437 /* Skip variable arguments. */
1438 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1439 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1440 return NULL;
1441
1442 /* In case of 'command \t', given src is NULL string. */
1443 if (src == NULL)
1444 return dst;
1445
1446 /* Matched with input string. */
1447 if (strncmp (src, dst, strlen (src)) == 0)
1448 return dst;
1449
1450 return NULL;
1451}
1452
1453/* If src matches dst return dst string, otherwise return NULL */
1454/* This version will return the dst string always if it is
1455 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001456static const char *
hasso8c328f12004-10-05 21:01:23 +00001457cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001458{
1459 if (CMD_VARARG (dst))
1460 return dst;
1461
1462 if (CMD_RANGE (dst))
1463 {
1464 if (cmd_range_match (dst, src))
1465 return dst;
1466 else
1467 return NULL;
1468 }
1469
paul22e0a9e2003-07-11 17:55:46 +00001470#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001471 if (CMD_IPV6 (dst))
1472 {
1473 if (cmd_ipv6_match (src))
1474 return dst;
1475 else
1476 return NULL;
1477 }
1478
1479 if (CMD_IPV6_PREFIX (dst))
1480 {
1481 if (cmd_ipv6_prefix_match (src))
1482 return dst;
1483 else
1484 return NULL;
1485 }
paul22e0a9e2003-07-11 17:55:46 +00001486#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001487
1488 if (CMD_IPV4 (dst))
1489 {
1490 if (cmd_ipv4_match (src))
1491 return dst;
1492 else
1493 return NULL;
1494 }
1495
1496 if (CMD_IPV4_PREFIX (dst))
1497 {
1498 if (cmd_ipv4_prefix_match (src))
1499 return dst;
1500 else
1501 return NULL;
1502 }
1503
1504 /* Optional or variable commands always match on '?' */
1505 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1506 return dst;
1507
1508 /* In case of 'command \t', given src is NULL string. */
1509 if (src == NULL)
1510 return dst;
1511
1512 if (strncmp (src, dst, strlen (src)) == 0)
1513 return dst;
1514 else
1515 return NULL;
1516}
1517
1518/* Check same string element existence. If it isn't there return
1519 1. */
ajs274a4a42004-12-07 15:39:31 +00001520static int
hasso8c328f12004-10-05 21:01:23 +00001521cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001522{
hasso8c328f12004-10-05 21:01:23 +00001523 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001524 char *match;
1525
1526 for (i = 0; i < vector_max (v); i++)
1527 if ((match = vector_slot (v, i)) != NULL)
1528 if (strcmp (match, str) == 0)
1529 return 0;
1530 return 1;
1531}
1532
1533/* Compare string to description vector. If there is same string
1534 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001535static int
hasso8c328f12004-10-05 21:01:23 +00001536desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001537{
hasso8c328f12004-10-05 21:01:23 +00001538 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001539 struct desc *desc;
1540
1541 for (i = 0; i < vector_max (v); i++)
1542 if ((desc = vector_slot (v, i)) != NULL)
1543 if (strcmp (desc->cmd, str) == 0)
1544 return 1;
1545 return 0;
1546}
1547
ajs274a4a42004-12-07 15:39:31 +00001548static int
paulb92938a2002-12-13 21:20:42 +00001549cmd_try_do_shortcut (enum node_type node, char* first_word) {
1550 if ( first_word != NULL &&
1551 node != AUTH_NODE &&
1552 node != VIEW_NODE &&
1553 node != AUTH_ENABLE_NODE &&
1554 node != ENABLE_NODE &&
1555 0 == strcmp( "do", first_word ) )
1556 return 1;
1557 return 0;
1558}
1559
paul718e3742002-12-13 20:15:29 +00001560/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001561static vector
paulb92938a2002-12-13 21:20:42 +00001562cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001563{
hassocba8a602005-01-02 18:51:01 +00001564 int i;
paul718e3742002-12-13 20:15:29 +00001565 vector cmd_vector;
1566#define INIT_MATCHVEC_SIZE 10
1567 vector matchvec;
1568 struct cmd_element *cmd_element;
hassocba8a602005-01-02 18:51:01 +00001569 int index;
paul54aba542003-08-21 20:28:24 +00001570 int ret;
1571 enum match_type match;
1572 char *command;
paul718e3742002-12-13 20:15:29 +00001573 static struct desc desc_cr = { "<cr>", "" };
1574
1575 /* Set index. */
1576 index = vector_max (vline) - 1;
1577
1578 /* Make copy vector of current node's command vector. */
1579 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1580
1581 /* Prepare match vector */
1582 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1583
1584 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001585 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001586 for (i = 0; i < index; i++)
1587 {
paul718e3742002-12-13 20:15:29 +00001588 command = vector_slot (vline, i);
paul718e3742002-12-13 20:15:29 +00001589 match = cmd_filter_by_completion (command, cmd_vector, i);
1590
1591 if (match == vararg_match)
1592 {
1593 struct cmd_element *cmd_element;
1594 vector descvec;
hasso8c328f12004-10-05 21:01:23 +00001595 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001596
1597 for (j = 0; j < vector_max (cmd_vector); j++)
1598 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL)
1599 {
1600 descvec = vector_slot (cmd_element->strvec,
1601 vector_max (cmd_element->strvec) - 1);
1602 for (k = 0; k < vector_max (descvec); k++)
1603 {
1604 struct desc *desc = vector_slot (descvec, k);
1605 vector_set (matchvec, desc);
1606 }
1607 }
1608
1609 vector_set (matchvec, &desc_cr);
paul718e3742002-12-13 20:15:29 +00001610 vector_free (cmd_vector);
1611
1612 return matchvec;
1613 }
1614
1615 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1616 {
1617 vector_free (cmd_vector);
1618 *status = CMD_ERR_AMBIGUOUS;
1619 return NULL;
1620 }
1621 else if (ret == 2)
1622 {
1623 vector_free (cmd_vector);
1624 *status = CMD_ERR_NO_MATCH;
1625 return NULL;
1626 }
1627 }
1628
1629 /* Prepare match vector */
1630 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1631
paul54aba542003-08-21 20:28:24 +00001632 /* Make sure that cmd_vector is filtered based on current word */
1633 command = vector_slot (vline, index);
1634 if (command)
1635 match = cmd_filter_by_completion (command, cmd_vector, index);
1636
paul718e3742002-12-13 20:15:29 +00001637 /* Make description vector. */
1638 for (i = 0; i < vector_max (cmd_vector); i++)
1639 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1640 {
hasso8c328f12004-10-05 21:01:23 +00001641 const char *string = NULL;
paul718e3742002-12-13 20:15:29 +00001642 vector strvec = cmd_element->strvec;
1643
paul54aba542003-08-21 20:28:24 +00001644 /* if command is NULL, index may be equal to vector_max */
1645 if (command && index >= vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001646 vector_slot (cmd_vector, i) = NULL;
1647 else
1648 {
paul54aba542003-08-21 20:28:24 +00001649 /* Check if command is completed. */
1650 if (command == NULL && index == vector_max (strvec))
paul718e3742002-12-13 20:15:29 +00001651 {
1652 string = "<cr>";
1653 if (! desc_unique_string (matchvec, string))
1654 vector_set (matchvec, &desc_cr);
1655 }
1656 else
1657 {
hasso8c328f12004-10-05 21:01:23 +00001658 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001659 vector descvec = vector_slot (strvec, index);
1660 struct desc *desc;
1661
1662 for (j = 0; j < vector_max (descvec); j++)
1663 {
1664 desc = vector_slot (descvec, j);
paul54aba542003-08-21 20:28:24 +00001665 string = cmd_entry_function_desc (command, desc->cmd);
paul718e3742002-12-13 20:15:29 +00001666 if (string)
1667 {
1668 /* Uniqueness check */
1669 if (! desc_unique_string (matchvec, string))
1670 vector_set (matchvec, desc);
1671 }
1672 }
1673 }
1674 }
1675 }
1676 vector_free (cmd_vector);
1677
1678 if (vector_slot (matchvec, 0) == NULL)
1679 {
1680 vector_free (matchvec);
1681 *status= CMD_ERR_NO_MATCH;
1682 }
1683 else
1684 *status = CMD_SUCCESS;
1685
1686 return matchvec;
1687}
1688
paulb92938a2002-12-13 21:20:42 +00001689vector
1690cmd_describe_command (vector vline, struct vty *vty, int *status)
1691{
1692 vector ret;
1693
1694 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1695 {
1696 enum node_type onode;
1697 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001698 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001699
1700 onode = vty->node;
1701 vty->node = ENABLE_NODE;
1702 /* We can try it on enable node, cos' the vty is authenticated */
1703
1704 shifted_vline = vector_init (vector_count(vline));
1705 /* use memcpy? */
1706 for (index = 1; index < vector_max (vline); index++)
1707 {
1708 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1709 }
1710
1711 ret = cmd_describe_command_real (shifted_vline, vty, status);
1712
1713 vector_free(shifted_vline);
1714 vty->node = onode;
1715 return ret;
1716 }
1717
1718
1719 return cmd_describe_command_real (vline, vty, status);
1720}
1721
1722
paul718e3742002-12-13 20:15:29 +00001723/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001724static int
paul718e3742002-12-13 20:15:29 +00001725cmd_lcd (char **matched)
1726{
1727 int i;
1728 int j;
1729 int lcd = -1;
1730 char *s1, *s2;
1731 char c1, c2;
1732
1733 if (matched[0] == NULL || matched[1] == NULL)
1734 return 0;
1735
1736 for (i = 1; matched[i] != NULL; i++)
1737 {
1738 s1 = matched[i - 1];
1739 s2 = matched[i];
1740
1741 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1742 if (c1 != c2)
1743 break;
1744
1745 if (lcd < 0)
1746 lcd = j;
1747 else
1748 {
1749 if (lcd > j)
1750 lcd = j;
1751 }
1752 }
1753 return lcd;
1754}
1755
1756/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001757static char **
paulb92938a2002-12-13 21:20:42 +00001758cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001759{
hassocba8a602005-01-02 18:51:01 +00001760 int i;
paul718e3742002-12-13 20:15:29 +00001761 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1762#define INIT_MATCHVEC_SIZE 10
1763 vector matchvec;
1764 struct cmd_element *cmd_element;
hassocba8a602005-01-02 18:51:01 +00001765 int index = vector_max (vline) - 1;
paul718e3742002-12-13 20:15:29 +00001766 char **match_str;
1767 struct desc *desc;
1768 vector descvec;
1769 char *command;
1770 int lcd;
1771
1772 /* First, filter by preceeding command string */
1773 for (i = 0; i < index; i++)
1774 {
1775 enum match_type match;
1776 int ret;
1777
1778 command = vector_slot (vline, i);
1779
1780 /* First try completion match, if there is exactly match return 1 */
1781 match = cmd_filter_by_completion (command, cmd_vector, i);
1782
1783 /* If there is exact match then filter ambiguous match else check
1784 ambiguousness. */
1785 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1786 {
1787 vector_free (cmd_vector);
1788 *status = CMD_ERR_AMBIGUOUS;
1789 return NULL;
1790 }
1791 /*
1792 else if (ret == 2)
1793 {
1794 vector_free (cmd_vector);
1795 *status = CMD_ERR_NO_MATCH;
1796 return NULL;
1797 }
1798 */
1799 }
1800
1801 /* Prepare match vector. */
1802 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1803
1804 /* Now we got into completion */
1805 for (i = 0; i < vector_max (cmd_vector); i++)
1806 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1807 {
hasso8c328f12004-10-05 21:01:23 +00001808 const char *string;
paul718e3742002-12-13 20:15:29 +00001809 vector strvec = cmd_element->strvec;
1810
1811 /* Check field length */
1812 if (index >= vector_max (strvec))
1813 vector_slot (cmd_vector, i) = NULL;
1814 else
1815 {
hasso8c328f12004-10-05 21:01:23 +00001816 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001817
1818 descvec = vector_slot (strvec, index);
1819 for (j = 0; j < vector_max (descvec); j++)
1820 {
1821 desc = vector_slot (descvec, j);
1822
1823 if ((string = cmd_entry_function (vector_slot (vline, index),
1824 desc->cmd)))
1825 if (cmd_unique_string (matchvec, string))
1826 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1827 }
1828 }
1829 }
1830
1831 /* We don't need cmd_vector any more. */
1832 vector_free (cmd_vector);
1833
1834 /* No matched command */
1835 if (vector_slot (matchvec, 0) == NULL)
1836 {
1837 vector_free (matchvec);
1838
1839 /* In case of 'command \t' pattern. Do you need '?' command at
1840 the end of the line. */
1841 if (vector_slot (vline, index) == '\0')
1842 *status = CMD_ERR_NOTHING_TODO;
1843 else
1844 *status = CMD_ERR_NO_MATCH;
1845 return NULL;
1846 }
1847
1848 /* Only one matched */
1849 if (vector_slot (matchvec, 1) == NULL)
1850 {
1851 match_str = (char **) matchvec->index;
1852 vector_only_wrapper_free (matchvec);
1853 *status = CMD_COMPLETE_FULL_MATCH;
1854 return match_str;
1855 }
1856 /* Make it sure last element is NULL. */
1857 vector_set (matchvec, NULL);
1858
1859 /* Check LCD of matched strings. */
1860 if (vector_slot (vline, index) != NULL)
1861 {
1862 lcd = cmd_lcd ((char **) matchvec->index);
1863
1864 if (lcd)
1865 {
1866 int len = strlen (vector_slot (vline, index));
1867
1868 if (len < lcd)
1869 {
1870 char *lcdstr;
1871
1872 lcdstr = XMALLOC (MTYPE_TMP, lcd + 1);
1873 memcpy (lcdstr, matchvec->index[0], lcd);
1874 lcdstr[lcd] = '\0';
1875
1876 /* match_str = (char **) &lcdstr; */
1877
1878 /* Free matchvec. */
1879 for (i = 0; i < vector_max (matchvec); i++)
1880 {
1881 if (vector_slot (matchvec, i))
1882 XFREE (MTYPE_TMP, vector_slot (matchvec, i));
1883 }
1884 vector_free (matchvec);
1885
1886 /* Make new matchvec. */
1887 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1888 vector_set (matchvec, lcdstr);
1889 match_str = (char **) matchvec->index;
1890 vector_only_wrapper_free (matchvec);
1891
1892 *status = CMD_COMPLETE_MATCH;
1893 return match_str;
1894 }
1895 }
1896 }
1897
1898 match_str = (char **) matchvec->index;
1899 vector_only_wrapper_free (matchvec);
1900 *status = CMD_COMPLETE_LIST_MATCH;
1901 return match_str;
1902}
1903
paulb92938a2002-12-13 21:20:42 +00001904char **
paul9ab68122003-01-18 01:16:20 +00001905cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001906{
1907 char **ret;
1908
1909 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1910 {
1911 enum node_type onode;
1912 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001913 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001914
1915 onode = vty->node;
1916 vty->node = ENABLE_NODE;
1917 /* We can try it on enable node, cos' the vty is authenticated */
1918
1919 shifted_vline = vector_init (vector_count(vline));
1920 /* use memcpy? */
1921 for (index = 1; index < vector_max (vline); index++)
1922 {
1923 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1924 }
1925
1926 ret = cmd_complete_command_real (shifted_vline, vty, status);
1927
1928 vector_free(shifted_vline);
1929 vty->node = onode;
1930 return ret;
1931 }
1932
1933
1934 return cmd_complete_command_real (vline, vty, status);
1935}
1936
1937/* return parent node */
1938/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001939enum node_type
ajs274a4a42004-12-07 15:39:31 +00001940node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001941{
1942 enum node_type ret;
1943
paul9ab68122003-01-18 01:16:20 +00001944 assert (node > CONFIG_NODE);
1945
1946 switch (node)
1947 {
1948 case BGP_VPNV4_NODE:
1949 case BGP_IPV4_NODE:
1950 case BGP_IPV4M_NODE:
1951 case BGP_IPV6_NODE:
1952 ret = BGP_NODE;
1953 break;
1954 case KEYCHAIN_KEY_NODE:
1955 ret = KEYCHAIN_NODE;
1956 break;
1957 default:
1958 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001959 }
1960
1961 return ret;
1962}
1963
paul718e3742002-12-13 20:15:29 +00001964/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001965static int
paulb92938a2002-12-13 21:20:42 +00001966cmd_execute_command_real (vector vline, struct vty *vty, struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001967{
hasso8c328f12004-10-05 21:01:23 +00001968 unsigned int i;
1969 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001970 vector cmd_vector;
1971 struct cmd_element *cmd_element;
1972 struct cmd_element *matched_element;
1973 unsigned int matched_count, incomplete_count;
1974 int argc;
paul9035efa2004-10-10 11:56:56 +00001975 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001976 enum match_type match = 0;
1977 int varflag;
1978 char *command;
1979
1980 /* Make copy of command elements. */
1981 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1982
1983 for (index = 0; index < vector_max (vline); index++)
1984 {
1985 int ret;
1986
1987 command = vector_slot (vline, index);
1988
1989 match = cmd_filter_by_completion (command, cmd_vector, index);
1990
1991 if (match == vararg_match)
1992 break;
1993
1994 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
1995
1996 if (ret == 1)
1997 {
1998 vector_free (cmd_vector);
1999 return CMD_ERR_AMBIGUOUS;
2000 }
2001 else if (ret == 2)
2002 {
2003 vector_free (cmd_vector);
2004 return CMD_ERR_NO_MATCH;
2005 }
2006 }
2007
2008 /* Check matched count. */
2009 matched_element = NULL;
2010 matched_count = 0;
2011 incomplete_count = 0;
2012
2013 for (i = 0; i < vector_max (cmd_vector); i++)
2014 if (vector_slot (cmd_vector,i) != NULL)
2015 {
2016 cmd_element = vector_slot (cmd_vector,i);
2017
2018 if (match == vararg_match || index >= cmd_element->cmdsize)
2019 {
2020 matched_element = cmd_element;
2021#if 0
2022 printf ("DEBUG: %s\n", cmd_element->string);
2023#endif
2024 matched_count++;
2025 }
2026 else
2027 {
2028 incomplete_count++;
2029 }
2030 }
2031
2032 /* Finish of using cmd_vector. */
2033 vector_free (cmd_vector);
2034
2035 /* To execute command, matched_count must be 1.*/
2036 if (matched_count == 0)
2037 {
2038 if (incomplete_count)
2039 return CMD_ERR_INCOMPLETE;
2040 else
2041 return CMD_ERR_NO_MATCH;
2042 }
2043
2044 if (matched_count > 1)
2045 return CMD_ERR_AMBIGUOUS;
2046
2047 /* Argument treatment */
2048 varflag = 0;
2049 argc = 0;
2050
2051 for (i = 0; i < vector_max (vline); i++)
2052 {
2053 if (varflag)
2054 argv[argc++] = vector_slot (vline, i);
2055 else
2056 {
2057 vector descvec = vector_slot (matched_element->strvec, i);
2058
2059 if (vector_max (descvec) == 1)
2060 {
2061 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002062
hasso8c328f12004-10-05 21:01:23 +00002063 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002064 varflag = 1;
2065
hasso8c328f12004-10-05 21:01:23 +00002066 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002067 argv[argc++] = vector_slot (vline, i);
2068 }
2069 else
2070 argv[argc++] = vector_slot (vline, i);
2071 }
2072
2073 if (argc >= CMD_ARGC_MAX)
2074 return CMD_ERR_EXEED_ARGC_MAX;
2075 }
2076
2077 /* For vtysh execution. */
2078 if (cmd)
2079 *cmd = matched_element;
2080
2081 if (matched_element->daemon)
2082 return CMD_SUCCESS_DAEMON;
2083
2084 /* Execute matched command. */
2085 return (*matched_element->func) (matched_element, vty, argc, argv);
2086}
2087
paulb92938a2002-12-13 21:20:42 +00002088
2089int
hasso87d683b2005-01-16 23:31:54 +00002090cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2091 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002092 int ret, saved_ret, tried = 0;
2093 enum node_type onode, try_node;
2094
2095 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002096
2097 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2098 {
2099 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002100 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002101
2102 vty->node = ENABLE_NODE;
2103 /* We can try it on enable node, cos' the vty is authenticated */
2104
2105 shifted_vline = vector_init (vector_count(vline));
2106 /* use memcpy? */
2107 for (index = 1; index < vector_max (vline); index++)
2108 {
2109 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2110 }
2111
2112 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2113
2114 vector_free(shifted_vline);
2115 vty->node = onode;
2116 return ret;
2117 }
2118
2119
paul9ab68122003-01-18 01:16:20 +00002120 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002121
hasso87d683b2005-01-16 23:31:54 +00002122 if (vtysh)
2123 return saved_ret;
2124
paulb92938a2002-12-13 21:20:42 +00002125 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002126 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002127 && vty->node > CONFIG_NODE )
2128 {
paul9ab68122003-01-18 01:16:20 +00002129 try_node = node_parent(try_node);
2130 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002131 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002132 tried = 1;
2133 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002134 {
paul9ab68122003-01-18 01:16:20 +00002135 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002136 return ret;
2137 }
paulb92938a2002-12-13 21:20:42 +00002138 }
paul9ab68122003-01-18 01:16:20 +00002139 /* no command succeeded, reset the vty to the original node and
2140 return the error for this node */
2141 if ( tried )
2142 vty->node = onode;
2143 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002144}
2145
paul718e3742002-12-13 20:15:29 +00002146/* Execute command by argument readline. */
2147int
2148cmd_execute_command_strict (vector vline, struct vty *vty,
2149 struct cmd_element **cmd)
2150{
hasso8c328f12004-10-05 21:01:23 +00002151 unsigned int i;
2152 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002153 vector cmd_vector;
2154 struct cmd_element *cmd_element;
2155 struct cmd_element *matched_element;
2156 unsigned int matched_count, incomplete_count;
2157 int argc;
paul9035efa2004-10-10 11:56:56 +00002158 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002159 int varflag;
2160 enum match_type match = 0;
2161 char *command;
2162
2163 /* Make copy of command element */
2164 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2165
2166 for (index = 0; index < vector_max (vline); index++)
2167 {
2168 int ret;
2169
2170 command = vector_slot (vline, index);
2171
2172 match = cmd_filter_by_string (vector_slot (vline, index),
2173 cmd_vector, index);
2174
2175 /* If command meets '.VARARG' then finish matching. */
2176 if (match == vararg_match)
2177 break;
2178
2179 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2180 if (ret == 1)
2181 {
2182 vector_free (cmd_vector);
2183 return CMD_ERR_AMBIGUOUS;
2184 }
2185 if (ret == 2)
2186 {
2187 vector_free (cmd_vector);
2188 return CMD_ERR_NO_MATCH;
2189 }
2190 }
2191
2192 /* Check matched count. */
2193 matched_element = NULL;
2194 matched_count = 0;
2195 incomplete_count = 0;
2196 for (i = 0; i < vector_max (cmd_vector); i++)
2197 if (vector_slot (cmd_vector,i) != NULL)
2198 {
2199 cmd_element = vector_slot (cmd_vector,i);
2200
2201 if (match == vararg_match || index >= cmd_element->cmdsize)
2202 {
2203 matched_element = cmd_element;
2204 matched_count++;
2205 }
2206 else
2207 incomplete_count++;
2208 }
2209
2210 /* Finish of using cmd_vector. */
2211 vector_free (cmd_vector);
2212
2213 /* To execute command, matched_count must be 1.*/
2214 if (matched_count == 0)
2215 {
2216 if (incomplete_count)
2217 return CMD_ERR_INCOMPLETE;
2218 else
2219 return CMD_ERR_NO_MATCH;
2220 }
2221
2222 if (matched_count > 1)
2223 return CMD_ERR_AMBIGUOUS;
2224
2225 /* Argument treatment */
2226 varflag = 0;
2227 argc = 0;
2228
2229 for (i = 0; i < vector_max (vline); i++)
2230 {
2231 if (varflag)
2232 argv[argc++] = vector_slot (vline, i);
2233 else
2234 {
2235 vector descvec = vector_slot (matched_element->strvec, i);
2236
2237 if (vector_max (descvec) == 1)
2238 {
2239 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002240
hasso8c328f12004-10-05 21:01:23 +00002241 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002242 varflag = 1;
2243
hasso8c328f12004-10-05 21:01:23 +00002244 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002245 argv[argc++] = vector_slot (vline, i);
2246 }
2247 else
2248 argv[argc++] = vector_slot (vline, i);
2249 }
2250
2251 if (argc >= CMD_ARGC_MAX)
2252 return CMD_ERR_EXEED_ARGC_MAX;
2253 }
2254
2255 /* For vtysh execution. */
2256 if (cmd)
2257 *cmd = matched_element;
2258
2259 if (matched_element->daemon)
2260 return CMD_SUCCESS_DAEMON;
2261
2262 /* Now execute matched command */
2263 return (*matched_element->func) (matched_element, vty, argc, argv);
2264}
2265
2266/* Configration make from file. */
2267int
2268config_from_file (struct vty *vty, FILE *fp)
2269{
2270 int ret;
2271 vector vline;
2272
2273 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2274 {
2275 vline = cmd_make_strvec (vty->buf);
2276
2277 /* In case of comment line */
2278 if (vline == NULL)
2279 continue;
2280 /* Execute configuration command : this is strict match */
2281 ret = cmd_execute_command_strict (vline, vty, NULL);
2282
2283 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002284 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002285 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2286 {
paulb92938a2002-12-13 21:20:42 +00002287 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002288 ret = cmd_execute_command_strict (vline, vty, NULL);
2289 }
paul9ab68122003-01-18 01:16:20 +00002290
paul718e3742002-12-13 20:15:29 +00002291 cmd_free_strvec (vline);
2292
hassoddd85ed2004-10-13 08:18:07 +00002293 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2294 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002295 return ret;
2296 }
2297 return CMD_SUCCESS;
2298}
2299
2300/* Configration from terminal */
2301DEFUN (config_terminal,
2302 config_terminal_cmd,
2303 "configure terminal",
2304 "Configuration from vty interface\n"
2305 "Configuration terminal\n")
2306{
2307 if (vty_config_lock (vty))
2308 vty->node = CONFIG_NODE;
2309 else
2310 {
2311 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2312 return CMD_WARNING;
2313 }
2314 return CMD_SUCCESS;
2315}
2316
2317/* Enable command */
2318DEFUN (enable,
2319 config_enable_cmd,
2320 "enable",
2321 "Turn on privileged mode command\n")
2322{
2323 /* If enable password is NULL, change to ENABLE_NODE */
2324 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2325 vty->type == VTY_SHELL_SERV)
2326 vty->node = ENABLE_NODE;
2327 else
2328 vty->node = AUTH_ENABLE_NODE;
2329
2330 return CMD_SUCCESS;
2331}
2332
2333/* Disable command */
2334DEFUN (disable,
2335 config_disable_cmd,
2336 "disable",
2337 "Turn off privileged mode command\n")
2338{
2339 if (vty->node == ENABLE_NODE)
2340 vty->node = VIEW_NODE;
2341 return CMD_SUCCESS;
2342}
2343
2344/* Down vty node level. */
2345DEFUN (config_exit,
2346 config_exit_cmd,
2347 "exit",
2348 "Exit current mode and down to previous mode\n")
2349{
2350 switch (vty->node)
2351 {
2352 case VIEW_NODE:
2353 case ENABLE_NODE:
2354 if (vty_shell (vty))
2355 exit (0);
2356 else
2357 vty->status = VTY_CLOSE;
2358 break;
2359 case CONFIG_NODE:
2360 vty->node = ENABLE_NODE;
2361 vty_config_unlock (vty);
2362 break;
2363 case INTERFACE_NODE:
2364 case ZEBRA_NODE:
2365 case BGP_NODE:
2366 case RIP_NODE:
2367 case RIPNG_NODE:
2368 case OSPF_NODE:
2369 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002370 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002371 case KEYCHAIN_NODE:
2372 case MASC_NODE:
2373 case RMAP_NODE:
2374 case VTY_NODE:
2375 vty->node = CONFIG_NODE;
2376 break;
2377 case BGP_VPNV4_NODE:
2378 case BGP_IPV4_NODE:
2379 case BGP_IPV4M_NODE:
2380 case BGP_IPV6_NODE:
2381 vty->node = BGP_NODE;
2382 break;
2383 case KEYCHAIN_KEY_NODE:
2384 vty->node = KEYCHAIN_NODE;
2385 break;
2386 default:
2387 break;
2388 }
2389 return CMD_SUCCESS;
2390}
2391
2392/* quit is alias of exit. */
2393ALIAS (config_exit,
2394 config_quit_cmd,
2395 "quit",
2396 "Exit current mode and down to previous mode\n")
2397
2398/* End of configuration. */
2399DEFUN (config_end,
2400 config_end_cmd,
2401 "end",
2402 "End current mode and change to enable mode.")
2403{
2404 switch (vty->node)
2405 {
2406 case VIEW_NODE:
2407 case ENABLE_NODE:
2408 /* Nothing to do. */
2409 break;
2410 case CONFIG_NODE:
2411 case INTERFACE_NODE:
2412 case ZEBRA_NODE:
2413 case RIP_NODE:
2414 case RIPNG_NODE:
2415 case BGP_NODE:
2416 case BGP_VPNV4_NODE:
2417 case BGP_IPV4_NODE:
2418 case BGP_IPV4M_NODE:
2419 case BGP_IPV6_NODE:
2420 case RMAP_NODE:
2421 case OSPF_NODE:
2422 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002423 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002424 case KEYCHAIN_NODE:
2425 case KEYCHAIN_KEY_NODE:
2426 case MASC_NODE:
2427 case VTY_NODE:
2428 vty_config_unlock (vty);
2429 vty->node = ENABLE_NODE;
2430 break;
2431 default:
2432 break;
2433 }
2434 return CMD_SUCCESS;
2435}
2436
2437/* Show version. */
2438DEFUN (show_version,
2439 show_version_cmd,
2440 "show version",
2441 SHOW_STR
2442 "Displays zebra version\n")
2443{
hasso12f6ea22005-03-07 08:35:39 +00002444 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2445 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002446 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002447
2448 return CMD_SUCCESS;
2449}
2450
2451/* Help display function for all node. */
2452DEFUN (config_help,
2453 config_help_cmd,
2454 "help",
2455 "Description of the interactive help system\n")
2456{
2457 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002458 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002459anytime at the command line please press '?'.%s\
2460%s\
2461If nothing matches, the help list will be empty and you must backup%s\
2462 until entering a '?' shows the available options.%s\
2463Two styles of help are provided:%s\
24641. Full help is available when you are ready to enter a%s\
2465command argument (e.g. 'show ?') and describes each possible%s\
2466argument.%s\
24672. Partial help is provided when an abbreviated argument is entered%s\
2468 and you want to know what arguments match the input%s\
2469 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2470 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2471 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2472 return CMD_SUCCESS;
2473}
2474
2475/* Help display function for all node. */
2476DEFUN (config_list,
2477 config_list_cmd,
2478 "list",
2479 "Print command list\n")
2480{
hasso8c328f12004-10-05 21:01:23 +00002481 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002482 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2483 struct cmd_element *cmd;
2484
2485 for (i = 0; i < vector_max (cnode->cmd_vector); i++)
2486 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL)
2487 vty_out (vty, " %s%s", cmd->string,
2488 VTY_NEWLINE);
2489 return CMD_SUCCESS;
2490}
2491
2492/* Write current configuration into file. */
2493DEFUN (config_write_file,
2494 config_write_file_cmd,
2495 "write file",
2496 "Write running configuration to memory, network, or terminal\n"
2497 "Write to configuration file\n")
2498{
hasso8c328f12004-10-05 21:01:23 +00002499 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002500 int fd;
2501 struct cmd_node *node;
2502 char *config_file;
2503 char *config_file_tmp = NULL;
2504 char *config_file_sav = NULL;
2505 struct vty *file_vty;
2506
2507 /* Check and see if we are operating under vtysh configuration */
2508 if (host.config == NULL)
2509 {
2510 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2511 VTY_NEWLINE);
2512 return CMD_WARNING;
2513 }
2514
2515 /* Get filename. */
2516 config_file = host.config;
2517
2518 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2519 strcpy (config_file_sav, config_file);
2520 strcat (config_file_sav, CONF_BACKUP_EXT);
2521
2522
2523 config_file_tmp = malloc (strlen (config_file) + 8);
2524 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2525
2526 /* Open file to configuration write. */
2527 fd = mkstemp (config_file_tmp);
2528 if (fd < 0)
2529 {
2530 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2531 VTY_NEWLINE);
2532 free (config_file_tmp);
2533 free (config_file_sav);
2534 return CMD_WARNING;
2535 }
2536
2537 /* Make vty for configuration file. */
2538 file_vty = vty_new ();
2539 file_vty->fd = fd;
2540 file_vty->type = VTY_FILE;
2541
2542 /* Config file header print. */
2543 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2544 vty_time_print (file_vty, 1);
2545 vty_out (file_vty, "!\n");
2546
2547 for (i = 0; i < vector_max (cmdvec); i++)
2548 if ((node = vector_slot (cmdvec, i)) && node->func)
2549 {
2550 if ((*node->func) (file_vty))
2551 vty_out (file_vty, "!\n");
2552 }
2553 vty_close (file_vty);
2554
2555 if (unlink (config_file_sav) != 0)
2556 if (errno != ENOENT)
2557 {
2558 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2559 VTY_NEWLINE);
2560 free (config_file_sav);
2561 free (config_file_tmp);
2562 unlink (config_file_tmp);
2563 return CMD_WARNING;
2564 }
2565 if (link (config_file, config_file_sav) != 0)
2566 {
2567 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2568 VTY_NEWLINE);
2569 free (config_file_sav);
2570 free (config_file_tmp);
2571 unlink (config_file_tmp);
2572 return CMD_WARNING;
2573 }
2574 sync ();
2575 if (unlink (config_file) != 0)
2576 {
2577 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2578 VTY_NEWLINE);
2579 free (config_file_sav);
2580 free (config_file_tmp);
2581 unlink (config_file_tmp);
2582 return CMD_WARNING;
2583 }
2584 if (link (config_file_tmp, config_file) != 0)
2585 {
2586 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2587 VTY_NEWLINE);
2588 free (config_file_sav);
2589 free (config_file_tmp);
2590 unlink (config_file_tmp);
2591 return CMD_WARNING;
2592 }
2593 unlink (config_file_tmp);
2594 sync ();
2595
2596 free (config_file_sav);
2597 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002598
2599 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2600 {
2601 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002602 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002603 return CMD_WARNING;
2604 }
2605
paul718e3742002-12-13 20:15:29 +00002606 vty_out (vty, "Configuration saved to %s%s", config_file,
2607 VTY_NEWLINE);
2608 return CMD_SUCCESS;
2609}
2610
2611ALIAS (config_write_file,
2612 config_write_cmd,
2613 "write",
2614 "Write running configuration to memory, network, or terminal\n")
2615
2616ALIAS (config_write_file,
2617 config_write_memory_cmd,
2618 "write memory",
2619 "Write running configuration to memory, network, or terminal\n"
2620 "Write configuration to the file (same as write file)\n")
2621
2622ALIAS (config_write_file,
2623 copy_runningconfig_startupconfig_cmd,
2624 "copy running-config startup-config",
2625 "Copy configuration\n"
2626 "Copy running config to... \n"
2627 "Copy running config to startup config (same as write file)\n")
2628
2629/* Write current configuration into the terminal. */
2630DEFUN (config_write_terminal,
2631 config_write_terminal_cmd,
2632 "write terminal",
2633 "Write running configuration to memory, network, or terminal\n"
2634 "Write to terminal\n")
2635{
hasso8c328f12004-10-05 21:01:23 +00002636 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002637 struct cmd_node *node;
2638
2639 if (vty->type == VTY_SHELL_SERV)
2640 {
2641 for (i = 0; i < vector_max (cmdvec); i++)
2642 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2643 {
2644 if ((*node->func) (vty))
2645 vty_out (vty, "!%s", VTY_NEWLINE);
2646 }
2647 }
2648 else
2649 {
2650 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2651 VTY_NEWLINE);
2652 vty_out (vty, "!%s", VTY_NEWLINE);
2653
2654 for (i = 0; i < vector_max (cmdvec); i++)
2655 if ((node = vector_slot (cmdvec, i)) && node->func)
2656 {
2657 if ((*node->func) (vty))
2658 vty_out (vty, "!%s", VTY_NEWLINE);
2659 }
2660 vty_out (vty, "end%s",VTY_NEWLINE);
2661 }
2662 return CMD_SUCCESS;
2663}
2664
2665/* Write current configuration into the terminal. */
2666ALIAS (config_write_terminal,
2667 show_running_config_cmd,
2668 "show running-config",
2669 SHOW_STR
2670 "running configuration\n")
2671
2672/* Write startup configuration into the terminal. */
2673DEFUN (show_startup_config,
2674 show_startup_config_cmd,
2675 "show startup-config",
2676 SHOW_STR
2677 "Contentes of startup configuration\n")
2678{
2679 char buf[BUFSIZ];
2680 FILE *confp;
2681
2682 confp = fopen (host.config, "r");
2683 if (confp == NULL)
2684 {
2685 vty_out (vty, "Can't open configuration file [%s]%s",
2686 host.config, VTY_NEWLINE);
2687 return CMD_WARNING;
2688 }
2689
2690 while (fgets (buf, BUFSIZ, confp))
2691 {
2692 char *cp = buf;
2693
2694 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2695 cp++;
2696 *cp = '\0';
2697
2698 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2699 }
2700
2701 fclose (confp);
2702
2703 return CMD_SUCCESS;
2704}
2705
2706/* Hostname configuration */
2707DEFUN (config_hostname,
2708 hostname_cmd,
2709 "hostname WORD",
2710 "Set system's network name\n"
2711 "This system's network name\n")
2712{
2713 if (!isalpha((int) *argv[0]))
2714 {
2715 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2716 return CMD_WARNING;
2717 }
2718
2719 if (host.name)
2720 XFREE (0, host.name);
2721
2722 host.name = strdup (argv[0]);
2723 return CMD_SUCCESS;
2724}
2725
2726DEFUN (config_no_hostname,
2727 no_hostname_cmd,
2728 "no hostname [HOSTNAME]",
2729 NO_STR
2730 "Reset system's network name\n"
2731 "Host name of this router\n")
2732{
2733 if (host.name)
2734 XFREE (0, host.name);
2735 host.name = NULL;
2736 return CMD_SUCCESS;
2737}
2738
2739/* VTY interface password set. */
2740DEFUN (config_password, password_cmd,
2741 "password (8|) WORD",
2742 "Assign the terminal connection password\n"
2743 "Specifies a HIDDEN password will follow\n"
2744 "dummy string \n"
2745 "The HIDDEN line password string\n")
2746{
2747 /* Argument check. */
2748 if (argc == 0)
2749 {
2750 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2751 return CMD_WARNING;
2752 }
2753
2754 if (argc == 2)
2755 {
2756 if (*argv[0] == '8')
2757 {
2758 if (host.password)
2759 XFREE (0, host.password);
2760 host.password = NULL;
2761 if (host.password_encrypt)
2762 XFREE (0, host.password_encrypt);
2763 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2764 return CMD_SUCCESS;
2765 }
2766 else
2767 {
2768 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2769 return CMD_WARNING;
2770 }
2771 }
2772
2773 if (!isalnum ((int) *argv[0]))
2774 {
2775 vty_out (vty,
2776 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2777 return CMD_WARNING;
2778 }
2779
2780 if (host.password)
2781 XFREE (0, host.password);
2782 host.password = NULL;
2783
2784 if (host.encrypt)
2785 {
2786 if (host.password_encrypt)
2787 XFREE (0, host.password_encrypt);
2788 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2789 }
2790 else
2791 host.password = XSTRDUP (0, argv[0]);
2792
2793 return CMD_SUCCESS;
2794}
2795
2796ALIAS (config_password, password_text_cmd,
2797 "password LINE",
2798 "Assign the terminal connection password\n"
2799 "The UNENCRYPTED (cleartext) line password\n")
2800
2801/* VTY enable password set. */
2802DEFUN (config_enable_password, enable_password_cmd,
2803 "enable password (8|) WORD",
2804 "Modify enable password parameters\n"
2805 "Assign the privileged level password\n"
2806 "Specifies a HIDDEN password will follow\n"
2807 "dummy string \n"
2808 "The HIDDEN 'enable' password string\n")
2809{
2810 /* Argument check. */
2811 if (argc == 0)
2812 {
2813 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2814 return CMD_WARNING;
2815 }
2816
2817 /* Crypt type is specified. */
2818 if (argc == 2)
2819 {
2820 if (*argv[0] == '8')
2821 {
2822 if (host.enable)
2823 XFREE (0, host.enable);
2824 host.enable = NULL;
2825
2826 if (host.enable_encrypt)
2827 XFREE (0, host.enable_encrypt);
2828 host.enable_encrypt = XSTRDUP (0, argv[1]);
2829
2830 return CMD_SUCCESS;
2831 }
2832 else
2833 {
2834 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2835 return CMD_WARNING;
2836 }
2837 }
2838
2839 if (!isalnum ((int) *argv[0]))
2840 {
2841 vty_out (vty,
2842 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2843 return CMD_WARNING;
2844 }
2845
2846 if (host.enable)
2847 XFREE (0, host.enable);
2848 host.enable = NULL;
2849
2850 /* Plain password input. */
2851 if (host.encrypt)
2852 {
2853 if (host.enable_encrypt)
2854 XFREE (0, host.enable_encrypt);
2855 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2856 }
2857 else
2858 host.enable = XSTRDUP (0, argv[0]);
2859
2860 return CMD_SUCCESS;
2861}
2862
2863ALIAS (config_enable_password,
2864 enable_password_text_cmd,
2865 "enable password LINE",
2866 "Modify enable password parameters\n"
2867 "Assign the privileged level password\n"
2868 "The UNENCRYPTED (cleartext) 'enable' password\n")
2869
2870/* VTY enable password delete. */
2871DEFUN (no_config_enable_password, no_enable_password_cmd,
2872 "no enable password",
2873 NO_STR
2874 "Modify enable password parameters\n"
2875 "Assign the privileged level password\n")
2876{
2877 if (host.enable)
2878 XFREE (0, host.enable);
2879 host.enable = NULL;
2880
2881 if (host.enable_encrypt)
2882 XFREE (0, host.enable_encrypt);
2883 host.enable_encrypt = NULL;
2884
2885 return CMD_SUCCESS;
2886}
2887
2888DEFUN (service_password_encrypt,
2889 service_password_encrypt_cmd,
2890 "service password-encryption",
2891 "Set up miscellaneous service\n"
2892 "Enable encrypted passwords\n")
2893{
2894 if (host.encrypt)
2895 return CMD_SUCCESS;
2896
2897 host.encrypt = 1;
2898
2899 if (host.password)
2900 {
2901 if (host.password_encrypt)
2902 XFREE (0, host.password_encrypt);
2903 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2904 }
2905 if (host.enable)
2906 {
2907 if (host.enable_encrypt)
2908 XFREE (0, host.enable_encrypt);
2909 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2910 }
2911
2912 return CMD_SUCCESS;
2913}
2914
2915DEFUN (no_service_password_encrypt,
2916 no_service_password_encrypt_cmd,
2917 "no service password-encryption",
2918 NO_STR
2919 "Set up miscellaneous service\n"
2920 "Enable encrypted passwords\n")
2921{
2922 if (! host.encrypt)
2923 return CMD_SUCCESS;
2924
2925 host.encrypt = 0;
2926
2927 if (host.password_encrypt)
2928 XFREE (0, host.password_encrypt);
2929 host.password_encrypt = NULL;
2930
2931 if (host.enable_encrypt)
2932 XFREE (0, host.enable_encrypt);
2933 host.enable_encrypt = NULL;
2934
2935 return CMD_SUCCESS;
2936}
2937
2938DEFUN (config_terminal_length, config_terminal_length_cmd,
2939 "terminal length <0-512>",
2940 "Set terminal line parameters\n"
2941 "Set number of lines on a screen\n"
2942 "Number of lines on screen (0 for no pausing)\n")
2943{
2944 int lines;
2945 char *endptr = NULL;
2946
2947 lines = strtol (argv[0], &endptr, 10);
2948 if (lines < 0 || lines > 512 || *endptr != '\0')
2949 {
2950 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2951 return CMD_WARNING;
2952 }
2953 vty->lines = lines;
2954
2955 return CMD_SUCCESS;
2956}
2957
2958DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2959 "terminal no length",
2960 "Set terminal line parameters\n"
2961 NO_STR
2962 "Set number of lines on a screen\n")
2963{
2964 vty->lines = -1;
2965 return CMD_SUCCESS;
2966}
2967
2968DEFUN (service_terminal_length, service_terminal_length_cmd,
2969 "service terminal-length <0-512>",
2970 "Set up miscellaneous service\n"
2971 "System wide terminal length configuration\n"
2972 "Number of lines of VTY (0 means no line control)\n")
2973{
2974 int lines;
2975 char *endptr = NULL;
2976
2977 lines = strtol (argv[0], &endptr, 10);
2978 if (lines < 0 || lines > 512 || *endptr != '\0')
2979 {
2980 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2981 return CMD_WARNING;
2982 }
2983 host.lines = lines;
2984
2985 return CMD_SUCCESS;
2986}
2987
2988DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2989 "no service terminal-length [<0-512>]",
2990 NO_STR
2991 "Set up miscellaneous service\n"
2992 "System wide terminal length configuration\n"
2993 "Number of lines of VTY (0 means no line control)\n")
2994{
2995 host.lines = -1;
2996 return CMD_SUCCESS;
2997}
2998
ajs2885f722004-12-17 23:16:33 +00002999DEFUN_HIDDEN (do_echo,
3000 echo_cmd,
3001 "echo .MESSAGE",
3002 "Echo a message back to the vty\n"
3003 "The message to echo\n")
3004{
3005 char *message;
3006
ajsf6834d42005-01-28 20:28:35 +00003007 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3008 VTY_NEWLINE);
3009 if (message)
3010 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003011 return CMD_SUCCESS;
3012}
3013
ajs274a4a42004-12-07 15:39:31 +00003014DEFUN (config_logmsg,
3015 config_logmsg_cmd,
3016 "logmsg "LOG_LEVELS" .MESSAGE",
3017 "Send a message to enabled logging destinations\n"
3018 LOG_LEVEL_DESC
3019 "The message to send\n")
3020{
3021 int level;
3022 char *message;
3023
3024 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3025 return CMD_ERR_NO_MATCH;
3026
ajsf6834d42005-01-28 20:28:35 +00003027 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3028 if (message)
3029 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003030 return CMD_SUCCESS;
3031}
3032
3033DEFUN (show_logging,
3034 show_logging_cmd,
3035 "show logging",
3036 SHOW_STR
3037 "Show current logging configuration\n")
3038{
3039 struct zlog *zl = zlog_default;
3040
3041 vty_out (vty, "Syslog logging: ");
3042 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3043 vty_out (vty, "disabled");
3044 else
3045 vty_out (vty, "level %s, facility %s, ident %s",
3046 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3047 facility_name(zl->facility), zl->ident);
3048 vty_out (vty, "%s", VTY_NEWLINE);
3049
3050 vty_out (vty, "Stdout logging: ");
3051 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3052 vty_out (vty, "disabled");
3053 else
3054 vty_out (vty, "level %s",
3055 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3056 vty_out (vty, "%s", VTY_NEWLINE);
3057
3058 vty_out (vty, "Monitor logging: ");
3059 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3060 vty_out (vty, "disabled");
3061 else
3062 vty_out (vty, "level %s",
3063 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3064 vty_out (vty, "%s", VTY_NEWLINE);
3065
3066 vty_out (vty, "File logging: ");
3067 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3068 !zl->fp)
3069 vty_out (vty, "disabled");
3070 else
3071 vty_out (vty, "level %s, filename %s",
3072 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3073 zl->filename);
3074 vty_out (vty, "%s", VTY_NEWLINE);
3075
3076 vty_out (vty, "Protocol name: %s%s",
3077 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3078 vty_out (vty, "Record priority: %s%s",
3079 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3080
3081 return CMD_SUCCESS;
3082}
3083
paul718e3742002-12-13 20:15:29 +00003084DEFUN (config_log_stdout,
3085 config_log_stdout_cmd,
3086 "log stdout",
3087 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003088 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003089{
ajs274a4a42004-12-07 15:39:31 +00003090 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3091 return CMD_SUCCESS;
3092}
3093
3094DEFUN (config_log_stdout_level,
3095 config_log_stdout_level_cmd,
3096 "log stdout "LOG_LEVELS,
3097 "Logging control\n"
3098 "Set stdout logging level\n"
3099 LOG_LEVEL_DESC)
3100{
3101 int level;
3102
3103 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3104 return CMD_ERR_NO_MATCH;
3105 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003106 return CMD_SUCCESS;
3107}
3108
3109DEFUN (no_config_log_stdout,
3110 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003111 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003112 NO_STR
3113 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003114 "Cancel logging to stdout\n"
3115 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003116{
ajs274a4a42004-12-07 15:39:31 +00003117 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003118 return CMD_SUCCESS;
3119}
3120
ajs274a4a42004-12-07 15:39:31 +00003121DEFUN (config_log_monitor,
3122 config_log_monitor_cmd,
3123 "log monitor",
paul718e3742002-12-13 20:15:29 +00003124 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003125 "Set terminal line (monitor) logging level\n")
3126{
3127 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3128 return CMD_SUCCESS;
3129}
3130
3131DEFUN (config_log_monitor_level,
3132 config_log_monitor_level_cmd,
3133 "log monitor "LOG_LEVELS,
3134 "Logging control\n"
3135 "Set terminal line (monitor) logging level\n"
3136 LOG_LEVEL_DESC)
3137{
3138 int level;
3139
3140 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3141 return CMD_ERR_NO_MATCH;
3142 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3143 return CMD_SUCCESS;
3144}
3145
3146DEFUN (no_config_log_monitor,
3147 no_config_log_monitor_cmd,
3148 "no log monitor [LEVEL]",
3149 NO_STR
3150 "Logging control\n"
3151 "Disable terminal line (monitor) logging\n"
3152 "Logging level\n")
3153{
3154 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3155 return CMD_SUCCESS;
3156}
3157
3158static int
3159set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003160{
3161 int ret;
paul9035efa2004-10-10 11:56:56 +00003162 char *p = NULL;
3163 const char *fullpath;
3164
paul718e3742002-12-13 20:15:29 +00003165 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003166 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003167 {
paul9035efa2004-10-10 11:56:56 +00003168 char cwd[MAXPATHLEN+1];
3169 cwd[MAXPATHLEN] = '\0';
3170
3171 if (getcwd (cwd, MAXPATHLEN) == NULL)
3172 {
3173 zlog_err ("config_log_file: Unable to alloc mem!");
3174 return CMD_WARNING;
3175 }
3176
ajs274a4a42004-12-07 15:39:31 +00003177 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003178 == NULL)
3179 {
3180 zlog_err ("config_log_file: Unable to alloc mem!");
3181 return CMD_WARNING;
3182 }
ajs274a4a42004-12-07 15:39:31 +00003183 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003184 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003185 }
3186 else
ajs274a4a42004-12-07 15:39:31 +00003187 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003188
ajs274a4a42004-12-07 15:39:31 +00003189 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003190
paul9035efa2004-10-10 11:56:56 +00003191 if (p)
3192 XFREE (MTYPE_TMP, p);
3193
paul718e3742002-12-13 20:15:29 +00003194 if (!ret)
3195 {
ajs274a4a42004-12-07 15:39:31 +00003196 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003197 return CMD_WARNING;
3198 }
3199
3200 if (host.logfile)
3201 XFREE (MTYPE_TMP, host.logfile);
3202
ajs274a4a42004-12-07 15:39:31 +00003203 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003204
3205 return CMD_SUCCESS;
3206}
3207
ajs274a4a42004-12-07 15:39:31 +00003208DEFUN (config_log_file,
3209 config_log_file_cmd,
3210 "log file FILENAME",
3211 "Logging control\n"
3212 "Logging to file\n"
3213 "Logging filename\n")
3214{
3215 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3216}
3217
3218DEFUN (config_log_file_level,
3219 config_log_file_level_cmd,
3220 "log file FILENAME "LOG_LEVELS,
3221 "Logging control\n"
3222 "Logging to file\n"
3223 "Logging filename\n"
3224 LOG_LEVEL_DESC)
3225{
3226 int level;
3227
3228 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3229 return CMD_ERR_NO_MATCH;
3230 return set_log_file(vty, argv[0], level);
3231}
3232
paul718e3742002-12-13 20:15:29 +00003233DEFUN (no_config_log_file,
3234 no_config_log_file_cmd,
3235 "no log file [FILENAME]",
3236 NO_STR
3237 "Logging control\n"
3238 "Cancel logging to file\n"
3239 "Logging file name\n")
3240{
3241 zlog_reset_file (NULL);
3242
3243 if (host.logfile)
3244 XFREE (MTYPE_TMP, host.logfile);
3245
3246 host.logfile = NULL;
3247
3248 return CMD_SUCCESS;
3249}
3250
ajs274a4a42004-12-07 15:39:31 +00003251ALIAS (no_config_log_file,
3252 no_config_log_file_level_cmd,
3253 "no log file FILENAME LEVEL",
3254 NO_STR
3255 "Logging control\n"
3256 "Cancel logging to file\n"
3257 "Logging file name\n"
3258 "Logging level\n")
3259
paul718e3742002-12-13 20:15:29 +00003260DEFUN (config_log_syslog,
3261 config_log_syslog_cmd,
3262 "log syslog",
3263 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003264 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003265{
ajs274a4a42004-12-07 15:39:31 +00003266 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003267 return CMD_SUCCESS;
3268}
3269
ajs274a4a42004-12-07 15:39:31 +00003270DEFUN (config_log_syslog_level,
3271 config_log_syslog_level_cmd,
3272 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003273 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003274 "Set syslog logging level\n"
3275 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003276{
ajs274a4a42004-12-07 15:39:31 +00003277 int level;
paul12ab19f2003-07-26 06:14:55 +00003278
ajs274a4a42004-12-07 15:39:31 +00003279 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3280 return CMD_ERR_NO_MATCH;
3281 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3282 return CMD_SUCCESS;
3283}
paul12ab19f2003-07-26 06:14:55 +00003284
ajs274a4a42004-12-07 15:39:31 +00003285DEFUN_DEPRECATED (config_log_syslog_facility,
3286 config_log_syslog_facility_cmd,
3287 "log syslog facility "LOG_FACILITIES,
3288 "Logging control\n"
3289 "Logging goes to syslog\n"
3290 "(Deprecated) Facility parameter for syslog messages\n"
3291 LOG_FACILITY_DESC)
3292{
3293 int facility;
paul12ab19f2003-07-26 06:14:55 +00003294
ajs274a4a42004-12-07 15:39:31 +00003295 if ((facility = facility_match(argv[0])) < 0)
3296 return CMD_ERR_NO_MATCH;
3297
3298 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003299 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003300 return CMD_SUCCESS;
3301}
3302
3303DEFUN (no_config_log_syslog,
3304 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003305 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003306 NO_STR
3307 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003308 "Cancel logging to syslog\n"
3309 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003310{
ajs274a4a42004-12-07 15:39:31 +00003311 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003312 return CMD_SUCCESS;
3313}
3314
paul12ab19f2003-07-26 06:14:55 +00003315ALIAS (no_config_log_syslog,
3316 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003317 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003318 NO_STR
3319 "Logging control\n"
3320 "Logging goes to syslog\n"
3321 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003322 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003323
ajs274a4a42004-12-07 15:39:31 +00003324DEFUN (config_log_facility,
3325 config_log_facility_cmd,
3326 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003327 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003328 "Facility parameter for syslog messages\n"
3329 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003330{
ajs274a4a42004-12-07 15:39:31 +00003331 int facility;
3332
3333 if ((facility = facility_match(argv[0])) < 0)
3334 return CMD_ERR_NO_MATCH;
3335 zlog_default->facility = facility;
3336 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003337}
3338
ajs274a4a42004-12-07 15:39:31 +00003339DEFUN (no_config_log_facility,
3340 no_config_log_facility_cmd,
3341 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003342 NO_STR
3343 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003344 "Reset syslog facility to default (daemon)\n"
3345 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003346{
ajs274a4a42004-12-07 15:39:31 +00003347 zlog_default->facility = LOG_DAEMON;
3348 return CMD_SUCCESS;
3349}
3350
3351DEFUN_DEPRECATED (config_log_trap,
3352 config_log_trap_cmd,
3353 "log trap "LOG_LEVELS,
3354 "Logging control\n"
3355 "(Deprecated) Set logging level and default for all destinations\n"
3356 LOG_LEVEL_DESC)
3357{
3358 int new_level ;
3359 int i;
3360
3361 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3362 return CMD_ERR_NO_MATCH;
3363
3364 zlog_default->default_lvl = new_level;
3365 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3366 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3367 zlog_default->maxlvl[i] = new_level;
3368 return CMD_SUCCESS;
3369}
3370
3371DEFUN_DEPRECATED (no_config_log_trap,
3372 no_config_log_trap_cmd,
3373 "no log trap [LEVEL]",
3374 NO_STR
3375 "Logging control\n"
3376 "Permit all logging information\n"
3377 "Logging level\n")
3378{
3379 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003380 return CMD_SUCCESS;
3381}
3382
3383DEFUN (config_log_record_priority,
3384 config_log_record_priority_cmd,
3385 "log record-priority",
3386 "Logging control\n"
3387 "Log the priority of the message within the message\n")
3388{
3389 zlog_default->record_priority = 1 ;
3390 return CMD_SUCCESS;
3391}
3392
3393DEFUN (no_config_log_record_priority,
3394 no_config_log_record_priority_cmd,
3395 "no log record-priority",
3396 NO_STR
3397 "Logging control\n"
3398 "Do not log the priority of the message within the message\n")
3399{
3400 zlog_default->record_priority = 0 ;
3401 return CMD_SUCCESS;
3402}
3403
paul3b0c5d92005-03-08 10:43:43 +00003404DEFUN (banner_motd_file,
3405 banner_motd_file_cmd,
3406 "banner motd file [FILE]",
3407 "Set banner\n"
3408 "Banner for motd\n"
3409 "Banner from a file\n"
3410 "Filename\n")
3411{
paulb45da6f2005-03-08 15:16:57 +00003412 if (host.motdfile)
3413 XFREE (MTYPE_TMP, host.motdfile);
3414 host.motdfile = XSTRDUP (MTYPE_TMP, argv[0]);
3415
paul3b0c5d92005-03-08 10:43:43 +00003416 return CMD_SUCCESS;
3417}
paul718e3742002-12-13 20:15:29 +00003418
3419DEFUN (banner_motd_default,
3420 banner_motd_default_cmd,
3421 "banner motd default",
3422 "Set banner string\n"
3423 "Strings for motd\n"
3424 "Default string\n")
3425{
3426 host.motd = default_motd;
3427 return CMD_SUCCESS;
3428}
3429
3430DEFUN (no_banner_motd,
3431 no_banner_motd_cmd,
3432 "no banner motd",
3433 NO_STR
3434 "Set banner string\n"
3435 "Strings for motd\n")
3436{
3437 host.motd = NULL;
paul3b0c5d92005-03-08 10:43:43 +00003438 if (host.motdfile) free(host.motdfile);
3439 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003440 return CMD_SUCCESS;
3441}
3442
3443/* Set config filename. Called from vty.c */
3444void
3445host_config_set (char *filename)
3446{
3447 host.config = strdup (filename);
3448}
3449
3450void
3451install_default (enum node_type node)
3452{
3453 install_element (node, &config_exit_cmd);
3454 install_element (node, &config_quit_cmd);
3455 install_element (node, &config_end_cmd);
3456 install_element (node, &config_help_cmd);
3457 install_element (node, &config_list_cmd);
3458
3459 install_element (node, &config_write_terminal_cmd);
3460 install_element (node, &config_write_file_cmd);
3461 install_element (node, &config_write_memory_cmd);
3462 install_element (node, &config_write_cmd);
3463 install_element (node, &show_running_config_cmd);
3464}
3465
3466/* Initialize command interface. Install basic nodes and commands. */
3467void
3468cmd_init (int terminal)
3469{
3470 /* Allocate initial top vector of commands. */
3471 cmdvec = vector_init (VECTOR_MIN_SIZE);
3472
3473 /* Default host value settings. */
3474 host.name = NULL;
3475 host.password = NULL;
3476 host.enable = NULL;
3477 host.logfile = NULL;
3478 host.config = NULL;
3479 host.lines = -1;
3480 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003481 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003482
3483 /* Install top nodes. */
3484 install_node (&view_node, NULL);
3485 install_node (&enable_node, NULL);
3486 install_node (&auth_node, NULL);
3487 install_node (&auth_enable_node, NULL);
3488 install_node (&config_node, config_write_host);
3489
3490 /* Each node's basic commands. */
3491 install_element (VIEW_NODE, &show_version_cmd);
3492 if (terminal)
3493 {
3494 install_element (VIEW_NODE, &config_list_cmd);
3495 install_element (VIEW_NODE, &config_exit_cmd);
3496 install_element (VIEW_NODE, &config_quit_cmd);
3497 install_element (VIEW_NODE, &config_help_cmd);
3498 install_element (VIEW_NODE, &config_enable_cmd);
3499 install_element (VIEW_NODE, &config_terminal_length_cmd);
3500 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003501 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003502 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003503 }
3504
3505 if (terminal)
3506 {
3507 install_default (ENABLE_NODE);
3508 install_element (ENABLE_NODE, &config_disable_cmd);
3509 install_element (ENABLE_NODE, &config_terminal_cmd);
3510 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3511 }
3512 install_element (ENABLE_NODE, &show_startup_config_cmd);
3513 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003514
3515 if (terminal)
paul718e3742002-12-13 20:15:29 +00003516 {
hassoe7168df2004-10-03 20:11:32 +00003517 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3518 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003519 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003520 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003521 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003522
3523 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003524 }
3525
3526 install_element (CONFIG_NODE, &hostname_cmd);
3527 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003528
hassoea8e9d92004-10-07 21:32:14 +00003529 if (terminal)
3530 {
hassoe7168df2004-10-03 20:11:32 +00003531 install_element (CONFIG_NODE, &password_cmd);
3532 install_element (CONFIG_NODE, &password_text_cmd);
3533 install_element (CONFIG_NODE, &enable_password_cmd);
3534 install_element (CONFIG_NODE, &enable_password_text_cmd);
3535 install_element (CONFIG_NODE, &no_enable_password_cmd);
3536
paul718e3742002-12-13 20:15:29 +00003537 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003538 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003539 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003540 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3541 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3542 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003543 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003544 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003545 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003546 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003547 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003548 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003549 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003550 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003551 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003552 install_element (CONFIG_NODE, &config_log_facility_cmd);
3553 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003554 install_element (CONFIG_NODE, &config_log_trap_cmd);
3555 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3556 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3557 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3558 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3559 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3560 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003561 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003562 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3563 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3564 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003565
paul9ab68122003-01-18 01:16:20 +00003566 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3567 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3568 }
paul718e3742002-12-13 20:15:29 +00003569 srand(time(NULL));
3570}