blob: abd7106ed4a13d76d1aff3f57fabd756cad9d597 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
paul4275b1d2005-03-09 13:42:23 +00002 $Id: command.c,v 1.43 2005/03/09 13:42:23 paul Exp $
paul9e92eea2005-03-09 13:39:26 +00003
ajs274a4a42004-12-07 15:39:31 +00004 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{
paul9e92eea2005-03-09 13:39:26 +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;
paul9e92eea2005-03-09 13:39:26 +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{
paul9e92eea2005-03-09 13:39:26 +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;
paul9e92eea2005-03-09 13:39:26 +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++)
paul4275b1d2005-03-09 13:42:23 +00002486 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2487 && !(cmd->attr == CMD_ATTR_DEPRECATED
2488 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002489 vty_out (vty, " %s%s", cmd->string,
2490 VTY_NEWLINE);
2491 return CMD_SUCCESS;
2492}
2493
2494/* Write current configuration into file. */
2495DEFUN (config_write_file,
2496 config_write_file_cmd,
2497 "write file",
2498 "Write running configuration to memory, network, or terminal\n"
2499 "Write to configuration file\n")
2500{
hasso8c328f12004-10-05 21:01:23 +00002501 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002502 int fd;
2503 struct cmd_node *node;
2504 char *config_file;
2505 char *config_file_tmp = NULL;
2506 char *config_file_sav = NULL;
2507 struct vty *file_vty;
2508
2509 /* Check and see if we are operating under vtysh configuration */
2510 if (host.config == NULL)
2511 {
2512 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2513 VTY_NEWLINE);
2514 return CMD_WARNING;
2515 }
2516
2517 /* Get filename. */
2518 config_file = host.config;
2519
2520 config_file_sav = malloc (strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
2521 strcpy (config_file_sav, config_file);
2522 strcat (config_file_sav, CONF_BACKUP_EXT);
2523
2524
2525 config_file_tmp = malloc (strlen (config_file) + 8);
2526 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2527
2528 /* Open file to configuration write. */
2529 fd = mkstemp (config_file_tmp);
2530 if (fd < 0)
2531 {
2532 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2533 VTY_NEWLINE);
2534 free (config_file_tmp);
2535 free (config_file_sav);
2536 return CMD_WARNING;
2537 }
2538
2539 /* Make vty for configuration file. */
2540 file_vty = vty_new ();
2541 file_vty->fd = fd;
2542 file_vty->type = VTY_FILE;
2543
2544 /* Config file header print. */
2545 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2546 vty_time_print (file_vty, 1);
2547 vty_out (file_vty, "!\n");
2548
2549 for (i = 0; i < vector_max (cmdvec); i++)
2550 if ((node = vector_slot (cmdvec, i)) && node->func)
2551 {
2552 if ((*node->func) (file_vty))
2553 vty_out (file_vty, "!\n");
2554 }
2555 vty_close (file_vty);
2556
2557 if (unlink (config_file_sav) != 0)
2558 if (errno != ENOENT)
2559 {
2560 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2561 VTY_NEWLINE);
2562 free (config_file_sav);
2563 free (config_file_tmp);
2564 unlink (config_file_tmp);
2565 return CMD_WARNING;
2566 }
2567 if (link (config_file, config_file_sav) != 0)
2568 {
2569 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2570 VTY_NEWLINE);
2571 free (config_file_sav);
2572 free (config_file_tmp);
2573 unlink (config_file_tmp);
2574 return CMD_WARNING;
2575 }
2576 sync ();
2577 if (unlink (config_file) != 0)
2578 {
2579 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2580 VTY_NEWLINE);
2581 free (config_file_sav);
2582 free (config_file_tmp);
2583 unlink (config_file_tmp);
2584 return CMD_WARNING;
2585 }
2586 if (link (config_file_tmp, config_file) != 0)
2587 {
2588 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2589 VTY_NEWLINE);
2590 free (config_file_sav);
2591 free (config_file_tmp);
2592 unlink (config_file_tmp);
2593 return CMD_WARNING;
2594 }
2595 unlink (config_file_tmp);
2596 sync ();
2597
2598 free (config_file_sav);
2599 free (config_file_tmp);
gdtaa593d52003-12-22 20:15:53 +00002600
2601 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2602 {
2603 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002604 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
gdtaa593d52003-12-22 20:15:53 +00002605 return CMD_WARNING;
2606 }
2607
paul718e3742002-12-13 20:15:29 +00002608 vty_out (vty, "Configuration saved to %s%s", config_file,
2609 VTY_NEWLINE);
2610 return CMD_SUCCESS;
2611}
2612
2613ALIAS (config_write_file,
2614 config_write_cmd,
2615 "write",
2616 "Write running configuration to memory, network, or terminal\n")
2617
2618ALIAS (config_write_file,
2619 config_write_memory_cmd,
2620 "write memory",
2621 "Write running configuration to memory, network, or terminal\n"
2622 "Write configuration to the file (same as write file)\n")
2623
2624ALIAS (config_write_file,
2625 copy_runningconfig_startupconfig_cmd,
2626 "copy running-config startup-config",
2627 "Copy configuration\n"
2628 "Copy running config to... \n"
2629 "Copy running config to startup config (same as write file)\n")
2630
2631/* Write current configuration into the terminal. */
2632DEFUN (config_write_terminal,
2633 config_write_terminal_cmd,
2634 "write terminal",
2635 "Write running configuration to memory, network, or terminal\n"
2636 "Write to terminal\n")
2637{
hasso8c328f12004-10-05 21:01:23 +00002638 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002639 struct cmd_node *node;
2640
2641 if (vty->type == VTY_SHELL_SERV)
2642 {
2643 for (i = 0; i < vector_max (cmdvec); i++)
2644 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2645 {
2646 if ((*node->func) (vty))
2647 vty_out (vty, "!%s", VTY_NEWLINE);
2648 }
2649 }
2650 else
2651 {
2652 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2653 VTY_NEWLINE);
2654 vty_out (vty, "!%s", VTY_NEWLINE);
2655
2656 for (i = 0; i < vector_max (cmdvec); i++)
2657 if ((node = vector_slot (cmdvec, i)) && node->func)
2658 {
2659 if ((*node->func) (vty))
2660 vty_out (vty, "!%s", VTY_NEWLINE);
2661 }
2662 vty_out (vty, "end%s",VTY_NEWLINE);
2663 }
2664 return CMD_SUCCESS;
2665}
2666
2667/* Write current configuration into the terminal. */
2668ALIAS (config_write_terminal,
2669 show_running_config_cmd,
2670 "show running-config",
2671 SHOW_STR
2672 "running configuration\n")
2673
2674/* Write startup configuration into the terminal. */
2675DEFUN (show_startup_config,
2676 show_startup_config_cmd,
2677 "show startup-config",
2678 SHOW_STR
2679 "Contentes of startup configuration\n")
2680{
2681 char buf[BUFSIZ];
2682 FILE *confp;
2683
2684 confp = fopen (host.config, "r");
2685 if (confp == NULL)
2686 {
2687 vty_out (vty, "Can't open configuration file [%s]%s",
2688 host.config, VTY_NEWLINE);
2689 return CMD_WARNING;
2690 }
2691
2692 while (fgets (buf, BUFSIZ, confp))
2693 {
2694 char *cp = buf;
2695
2696 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2697 cp++;
2698 *cp = '\0';
2699
2700 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2701 }
2702
2703 fclose (confp);
2704
2705 return CMD_SUCCESS;
2706}
2707
2708/* Hostname configuration */
2709DEFUN (config_hostname,
2710 hostname_cmd,
2711 "hostname WORD",
2712 "Set system's network name\n"
2713 "This system's network name\n")
2714{
2715 if (!isalpha((int) *argv[0]))
2716 {
2717 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2718 return CMD_WARNING;
2719 }
2720
2721 if (host.name)
2722 XFREE (0, host.name);
2723
2724 host.name = strdup (argv[0]);
2725 return CMD_SUCCESS;
2726}
2727
2728DEFUN (config_no_hostname,
2729 no_hostname_cmd,
2730 "no hostname [HOSTNAME]",
2731 NO_STR
2732 "Reset system's network name\n"
2733 "Host name of this router\n")
2734{
2735 if (host.name)
2736 XFREE (0, host.name);
2737 host.name = NULL;
2738 return CMD_SUCCESS;
2739}
2740
2741/* VTY interface password set. */
2742DEFUN (config_password, password_cmd,
2743 "password (8|) WORD",
2744 "Assign the terminal connection password\n"
2745 "Specifies a HIDDEN password will follow\n"
2746 "dummy string \n"
2747 "The HIDDEN line password string\n")
2748{
2749 /* Argument check. */
2750 if (argc == 0)
2751 {
2752 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2753 return CMD_WARNING;
2754 }
2755
2756 if (argc == 2)
2757 {
2758 if (*argv[0] == '8')
2759 {
2760 if (host.password)
2761 XFREE (0, host.password);
2762 host.password = NULL;
2763 if (host.password_encrypt)
2764 XFREE (0, host.password_encrypt);
2765 host.password_encrypt = XSTRDUP (0, strdup (argv[1]));
2766 return CMD_SUCCESS;
2767 }
2768 else
2769 {
2770 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2771 return CMD_WARNING;
2772 }
2773 }
2774
2775 if (!isalnum ((int) *argv[0]))
2776 {
2777 vty_out (vty,
2778 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2779 return CMD_WARNING;
2780 }
2781
2782 if (host.password)
2783 XFREE (0, host.password);
2784 host.password = NULL;
2785
2786 if (host.encrypt)
2787 {
2788 if (host.password_encrypt)
2789 XFREE (0, host.password_encrypt);
2790 host.password_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2791 }
2792 else
2793 host.password = XSTRDUP (0, argv[0]);
2794
2795 return CMD_SUCCESS;
2796}
2797
2798ALIAS (config_password, password_text_cmd,
2799 "password LINE",
2800 "Assign the terminal connection password\n"
2801 "The UNENCRYPTED (cleartext) line password\n")
2802
2803/* VTY enable password set. */
2804DEFUN (config_enable_password, enable_password_cmd,
2805 "enable password (8|) WORD",
2806 "Modify enable password parameters\n"
2807 "Assign the privileged level password\n"
2808 "Specifies a HIDDEN password will follow\n"
2809 "dummy string \n"
2810 "The HIDDEN 'enable' password string\n")
2811{
2812 /* Argument check. */
2813 if (argc == 0)
2814 {
2815 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2816 return CMD_WARNING;
2817 }
2818
2819 /* Crypt type is specified. */
2820 if (argc == 2)
2821 {
2822 if (*argv[0] == '8')
2823 {
2824 if (host.enable)
2825 XFREE (0, host.enable);
2826 host.enable = NULL;
2827
2828 if (host.enable_encrypt)
2829 XFREE (0, host.enable_encrypt);
2830 host.enable_encrypt = XSTRDUP (0, argv[1]);
2831
2832 return CMD_SUCCESS;
2833 }
2834 else
2835 {
2836 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2837 return CMD_WARNING;
2838 }
2839 }
2840
2841 if (!isalnum ((int) *argv[0]))
2842 {
2843 vty_out (vty,
2844 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2845 return CMD_WARNING;
2846 }
2847
2848 if (host.enable)
2849 XFREE (0, host.enable);
2850 host.enable = NULL;
2851
2852 /* Plain password input. */
2853 if (host.encrypt)
2854 {
2855 if (host.enable_encrypt)
2856 XFREE (0, host.enable_encrypt);
2857 host.enable_encrypt = XSTRDUP (0, zencrypt (argv[0]));
2858 }
2859 else
2860 host.enable = XSTRDUP (0, argv[0]);
2861
2862 return CMD_SUCCESS;
2863}
2864
2865ALIAS (config_enable_password,
2866 enable_password_text_cmd,
2867 "enable password LINE",
2868 "Modify enable password parameters\n"
2869 "Assign the privileged level password\n"
2870 "The UNENCRYPTED (cleartext) 'enable' password\n")
2871
2872/* VTY enable password delete. */
2873DEFUN (no_config_enable_password, no_enable_password_cmd,
2874 "no enable password",
2875 NO_STR
2876 "Modify enable password parameters\n"
2877 "Assign the privileged level password\n")
2878{
2879 if (host.enable)
2880 XFREE (0, host.enable);
2881 host.enable = NULL;
2882
2883 if (host.enable_encrypt)
2884 XFREE (0, host.enable_encrypt);
2885 host.enable_encrypt = NULL;
2886
2887 return CMD_SUCCESS;
2888}
2889
2890DEFUN (service_password_encrypt,
2891 service_password_encrypt_cmd,
2892 "service password-encryption",
2893 "Set up miscellaneous service\n"
2894 "Enable encrypted passwords\n")
2895{
2896 if (host.encrypt)
2897 return CMD_SUCCESS;
2898
2899 host.encrypt = 1;
2900
2901 if (host.password)
2902 {
2903 if (host.password_encrypt)
2904 XFREE (0, host.password_encrypt);
2905 host.password_encrypt = XSTRDUP (0, zencrypt (host.password));
2906 }
2907 if (host.enable)
2908 {
2909 if (host.enable_encrypt)
2910 XFREE (0, host.enable_encrypt);
2911 host.enable_encrypt = XSTRDUP (0, zencrypt (host.enable));
2912 }
2913
2914 return CMD_SUCCESS;
2915}
2916
2917DEFUN (no_service_password_encrypt,
2918 no_service_password_encrypt_cmd,
2919 "no service password-encryption",
2920 NO_STR
2921 "Set up miscellaneous service\n"
2922 "Enable encrypted passwords\n")
2923{
2924 if (! host.encrypt)
2925 return CMD_SUCCESS;
2926
2927 host.encrypt = 0;
2928
2929 if (host.password_encrypt)
2930 XFREE (0, host.password_encrypt);
2931 host.password_encrypt = NULL;
2932
2933 if (host.enable_encrypt)
2934 XFREE (0, host.enable_encrypt);
2935 host.enable_encrypt = NULL;
2936
2937 return CMD_SUCCESS;
2938}
2939
2940DEFUN (config_terminal_length, config_terminal_length_cmd,
2941 "terminal length <0-512>",
2942 "Set terminal line parameters\n"
2943 "Set number of lines on a screen\n"
2944 "Number of lines on screen (0 for no pausing)\n")
2945{
2946 int lines;
2947 char *endptr = NULL;
2948
2949 lines = strtol (argv[0], &endptr, 10);
2950 if (lines < 0 || lines > 512 || *endptr != '\0')
2951 {
2952 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2953 return CMD_WARNING;
2954 }
2955 vty->lines = lines;
2956
2957 return CMD_SUCCESS;
2958}
2959
2960DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2961 "terminal no length",
2962 "Set terminal line parameters\n"
2963 NO_STR
2964 "Set number of lines on a screen\n")
2965{
2966 vty->lines = -1;
2967 return CMD_SUCCESS;
2968}
2969
2970DEFUN (service_terminal_length, service_terminal_length_cmd,
2971 "service terminal-length <0-512>",
2972 "Set up miscellaneous service\n"
2973 "System wide terminal length configuration\n"
2974 "Number of lines of VTY (0 means no line control)\n")
2975{
2976 int lines;
2977 char *endptr = NULL;
2978
2979 lines = strtol (argv[0], &endptr, 10);
2980 if (lines < 0 || lines > 512 || *endptr != '\0')
2981 {
2982 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2983 return CMD_WARNING;
2984 }
2985 host.lines = lines;
2986
2987 return CMD_SUCCESS;
2988}
2989
2990DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2991 "no service terminal-length [<0-512>]",
2992 NO_STR
2993 "Set up miscellaneous service\n"
2994 "System wide terminal length configuration\n"
2995 "Number of lines of VTY (0 means no line control)\n")
2996{
2997 host.lines = -1;
2998 return CMD_SUCCESS;
2999}
3000
ajs2885f722004-12-17 23:16:33 +00003001DEFUN_HIDDEN (do_echo,
3002 echo_cmd,
3003 "echo .MESSAGE",
3004 "Echo a message back to the vty\n"
3005 "The message to echo\n")
3006{
3007 char *message;
3008
ajsf6834d42005-01-28 20:28:35 +00003009 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3010 VTY_NEWLINE);
3011 if (message)
3012 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003013 return CMD_SUCCESS;
3014}
3015
ajs274a4a42004-12-07 15:39:31 +00003016DEFUN (config_logmsg,
3017 config_logmsg_cmd,
3018 "logmsg "LOG_LEVELS" .MESSAGE",
3019 "Send a message to enabled logging destinations\n"
3020 LOG_LEVEL_DESC
3021 "The message to send\n")
3022{
3023 int level;
3024 char *message;
3025
3026 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3027 return CMD_ERR_NO_MATCH;
3028
ajsf6834d42005-01-28 20:28:35 +00003029 zlog(NULL, level, ((message = argv_concat(argv, argc, 1)) ? message : ""));
3030 if (message)
3031 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003032 return CMD_SUCCESS;
3033}
3034
3035DEFUN (show_logging,
3036 show_logging_cmd,
3037 "show logging",
3038 SHOW_STR
3039 "Show current logging configuration\n")
3040{
3041 struct zlog *zl = zlog_default;
3042
3043 vty_out (vty, "Syslog logging: ");
3044 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3045 vty_out (vty, "disabled");
3046 else
3047 vty_out (vty, "level %s, facility %s, ident %s",
3048 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3049 facility_name(zl->facility), zl->ident);
3050 vty_out (vty, "%s", VTY_NEWLINE);
3051
3052 vty_out (vty, "Stdout logging: ");
3053 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3054 vty_out (vty, "disabled");
3055 else
3056 vty_out (vty, "level %s",
3057 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3058 vty_out (vty, "%s", VTY_NEWLINE);
3059
3060 vty_out (vty, "Monitor logging: ");
3061 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3062 vty_out (vty, "disabled");
3063 else
3064 vty_out (vty, "level %s",
3065 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3066 vty_out (vty, "%s", VTY_NEWLINE);
3067
3068 vty_out (vty, "File logging: ");
3069 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3070 !zl->fp)
3071 vty_out (vty, "disabled");
3072 else
3073 vty_out (vty, "level %s, filename %s",
3074 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3075 zl->filename);
3076 vty_out (vty, "%s", VTY_NEWLINE);
3077
3078 vty_out (vty, "Protocol name: %s%s",
3079 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3080 vty_out (vty, "Record priority: %s%s",
3081 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
3082
3083 return CMD_SUCCESS;
3084}
3085
paul718e3742002-12-13 20:15:29 +00003086DEFUN (config_log_stdout,
3087 config_log_stdout_cmd,
3088 "log stdout",
3089 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003090 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003091{
ajs274a4a42004-12-07 15:39:31 +00003092 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3093 return CMD_SUCCESS;
3094}
3095
3096DEFUN (config_log_stdout_level,
3097 config_log_stdout_level_cmd,
3098 "log stdout "LOG_LEVELS,
3099 "Logging control\n"
3100 "Set stdout logging level\n"
3101 LOG_LEVEL_DESC)
3102{
3103 int level;
3104
3105 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3106 return CMD_ERR_NO_MATCH;
3107 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003108 return CMD_SUCCESS;
3109}
3110
3111DEFUN (no_config_log_stdout,
3112 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003113 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003114 NO_STR
3115 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003116 "Cancel logging to stdout\n"
3117 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003118{
ajs274a4a42004-12-07 15:39:31 +00003119 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003120 return CMD_SUCCESS;
3121}
3122
ajs274a4a42004-12-07 15:39:31 +00003123DEFUN (config_log_monitor,
3124 config_log_monitor_cmd,
3125 "log monitor",
paul718e3742002-12-13 20:15:29 +00003126 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003127 "Set terminal line (monitor) logging level\n")
3128{
3129 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3130 return CMD_SUCCESS;
3131}
3132
3133DEFUN (config_log_monitor_level,
3134 config_log_monitor_level_cmd,
3135 "log monitor "LOG_LEVELS,
3136 "Logging control\n"
3137 "Set terminal line (monitor) logging level\n"
3138 LOG_LEVEL_DESC)
3139{
3140 int level;
3141
3142 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3143 return CMD_ERR_NO_MATCH;
3144 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3145 return CMD_SUCCESS;
3146}
3147
3148DEFUN (no_config_log_monitor,
3149 no_config_log_monitor_cmd,
3150 "no log monitor [LEVEL]",
3151 NO_STR
3152 "Logging control\n"
3153 "Disable terminal line (monitor) logging\n"
3154 "Logging level\n")
3155{
3156 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3157 return CMD_SUCCESS;
3158}
3159
3160static int
3161set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003162{
3163 int ret;
paul9035efa2004-10-10 11:56:56 +00003164 char *p = NULL;
3165 const char *fullpath;
3166
paul718e3742002-12-13 20:15:29 +00003167 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003168 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003169 {
paul9035efa2004-10-10 11:56:56 +00003170 char cwd[MAXPATHLEN+1];
3171 cwd[MAXPATHLEN] = '\0';
3172
3173 if (getcwd (cwd, MAXPATHLEN) == NULL)
3174 {
3175 zlog_err ("config_log_file: Unable to alloc mem!");
3176 return CMD_WARNING;
3177 }
3178
ajs274a4a42004-12-07 15:39:31 +00003179 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003180 == NULL)
3181 {
3182 zlog_err ("config_log_file: Unable to alloc mem!");
3183 return CMD_WARNING;
3184 }
ajs274a4a42004-12-07 15:39:31 +00003185 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003186 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003187 }
3188 else
ajs274a4a42004-12-07 15:39:31 +00003189 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003190
ajs274a4a42004-12-07 15:39:31 +00003191 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003192
paul9035efa2004-10-10 11:56:56 +00003193 if (p)
3194 XFREE (MTYPE_TMP, p);
3195
paul718e3742002-12-13 20:15:29 +00003196 if (!ret)
3197 {
ajs274a4a42004-12-07 15:39:31 +00003198 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003199 return CMD_WARNING;
3200 }
3201
3202 if (host.logfile)
3203 XFREE (MTYPE_TMP, host.logfile);
3204
ajs274a4a42004-12-07 15:39:31 +00003205 host.logfile = XSTRDUP (MTYPE_TMP, fname);
paul718e3742002-12-13 20:15:29 +00003206
3207 return CMD_SUCCESS;
3208}
3209
ajs274a4a42004-12-07 15:39:31 +00003210DEFUN (config_log_file,
3211 config_log_file_cmd,
3212 "log file FILENAME",
3213 "Logging control\n"
3214 "Logging to file\n"
3215 "Logging filename\n")
3216{
3217 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3218}
3219
3220DEFUN (config_log_file_level,
3221 config_log_file_level_cmd,
3222 "log file FILENAME "LOG_LEVELS,
3223 "Logging control\n"
3224 "Logging to file\n"
3225 "Logging filename\n"
3226 LOG_LEVEL_DESC)
3227{
3228 int level;
3229
3230 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3231 return CMD_ERR_NO_MATCH;
3232 return set_log_file(vty, argv[0], level);
3233}
3234
paul718e3742002-12-13 20:15:29 +00003235DEFUN (no_config_log_file,
3236 no_config_log_file_cmd,
3237 "no log file [FILENAME]",
3238 NO_STR
3239 "Logging control\n"
3240 "Cancel logging to file\n"
3241 "Logging file name\n")
3242{
3243 zlog_reset_file (NULL);
3244
3245 if (host.logfile)
3246 XFREE (MTYPE_TMP, host.logfile);
3247
3248 host.logfile = NULL;
3249
3250 return CMD_SUCCESS;
3251}
3252
ajs274a4a42004-12-07 15:39:31 +00003253ALIAS (no_config_log_file,
3254 no_config_log_file_level_cmd,
3255 "no log file FILENAME LEVEL",
3256 NO_STR
3257 "Logging control\n"
3258 "Cancel logging to file\n"
3259 "Logging file name\n"
3260 "Logging level\n")
3261
paul718e3742002-12-13 20:15:29 +00003262DEFUN (config_log_syslog,
3263 config_log_syslog_cmd,
3264 "log syslog",
3265 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003266 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003267{
ajs274a4a42004-12-07 15:39:31 +00003268 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003269 return CMD_SUCCESS;
3270}
3271
ajs274a4a42004-12-07 15:39:31 +00003272DEFUN (config_log_syslog_level,
3273 config_log_syslog_level_cmd,
3274 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003275 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003276 "Set syslog logging level\n"
3277 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003278{
ajs274a4a42004-12-07 15:39:31 +00003279 int level;
paul12ab19f2003-07-26 06:14:55 +00003280
ajs274a4a42004-12-07 15:39:31 +00003281 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3282 return CMD_ERR_NO_MATCH;
3283 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3284 return CMD_SUCCESS;
3285}
paul12ab19f2003-07-26 06:14:55 +00003286
ajs274a4a42004-12-07 15:39:31 +00003287DEFUN_DEPRECATED (config_log_syslog_facility,
3288 config_log_syslog_facility_cmd,
3289 "log syslog facility "LOG_FACILITIES,
3290 "Logging control\n"
3291 "Logging goes to syslog\n"
3292 "(Deprecated) Facility parameter for syslog messages\n"
3293 LOG_FACILITY_DESC)
3294{
3295 int facility;
paul12ab19f2003-07-26 06:14:55 +00003296
ajs274a4a42004-12-07 15:39:31 +00003297 if ((facility = facility_match(argv[0])) < 0)
3298 return CMD_ERR_NO_MATCH;
3299
3300 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003301 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003302 return CMD_SUCCESS;
3303}
3304
3305DEFUN (no_config_log_syslog,
3306 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003307 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003308 NO_STR
3309 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003310 "Cancel logging to syslog\n"
3311 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003312{
ajs274a4a42004-12-07 15:39:31 +00003313 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003314 return CMD_SUCCESS;
3315}
3316
paul12ab19f2003-07-26 06:14:55 +00003317ALIAS (no_config_log_syslog,
3318 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003319 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003320 NO_STR
3321 "Logging control\n"
3322 "Logging goes to syslog\n"
3323 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003324 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003325
ajs274a4a42004-12-07 15:39:31 +00003326DEFUN (config_log_facility,
3327 config_log_facility_cmd,
3328 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003329 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003330 "Facility parameter for syslog messages\n"
3331 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003332{
ajs274a4a42004-12-07 15:39:31 +00003333 int facility;
3334
3335 if ((facility = facility_match(argv[0])) < 0)
3336 return CMD_ERR_NO_MATCH;
3337 zlog_default->facility = facility;
3338 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003339}
3340
ajs274a4a42004-12-07 15:39:31 +00003341DEFUN (no_config_log_facility,
3342 no_config_log_facility_cmd,
3343 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003344 NO_STR
3345 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003346 "Reset syslog facility to default (daemon)\n"
3347 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003348{
ajs274a4a42004-12-07 15:39:31 +00003349 zlog_default->facility = LOG_DAEMON;
3350 return CMD_SUCCESS;
3351}
3352
3353DEFUN_DEPRECATED (config_log_trap,
3354 config_log_trap_cmd,
3355 "log trap "LOG_LEVELS,
3356 "Logging control\n"
3357 "(Deprecated) Set logging level and default for all destinations\n"
3358 LOG_LEVEL_DESC)
3359{
3360 int new_level ;
3361 int i;
3362
3363 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3364 return CMD_ERR_NO_MATCH;
3365
3366 zlog_default->default_lvl = new_level;
3367 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3368 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3369 zlog_default->maxlvl[i] = new_level;
3370 return CMD_SUCCESS;
3371}
3372
3373DEFUN_DEPRECATED (no_config_log_trap,
3374 no_config_log_trap_cmd,
3375 "no log trap [LEVEL]",
3376 NO_STR
3377 "Logging control\n"
3378 "Permit all logging information\n"
3379 "Logging level\n")
3380{
3381 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003382 return CMD_SUCCESS;
3383}
3384
3385DEFUN (config_log_record_priority,
3386 config_log_record_priority_cmd,
3387 "log record-priority",
3388 "Logging control\n"
3389 "Log the priority of the message within the message\n")
3390{
3391 zlog_default->record_priority = 1 ;
3392 return CMD_SUCCESS;
3393}
3394
3395DEFUN (no_config_log_record_priority,
3396 no_config_log_record_priority_cmd,
3397 "no log record-priority",
3398 NO_STR
3399 "Logging control\n"
3400 "Do not log the priority of the message within the message\n")
3401{
3402 zlog_default->record_priority = 0 ;
3403 return CMD_SUCCESS;
3404}
3405
paul3b0c5d92005-03-08 10:43:43 +00003406DEFUN (banner_motd_file,
3407 banner_motd_file_cmd,
3408 "banner motd file [FILE]",
3409 "Set banner\n"
3410 "Banner for motd\n"
3411 "Banner from a file\n"
3412 "Filename\n")
3413{
paulb45da6f2005-03-08 15:16:57 +00003414 if (host.motdfile)
3415 XFREE (MTYPE_TMP, host.motdfile);
3416 host.motdfile = XSTRDUP (MTYPE_TMP, argv[0]);
3417
paul3b0c5d92005-03-08 10:43:43 +00003418 return CMD_SUCCESS;
3419}
paul718e3742002-12-13 20:15:29 +00003420
3421DEFUN (banner_motd_default,
3422 banner_motd_default_cmd,
3423 "banner motd default",
3424 "Set banner string\n"
3425 "Strings for motd\n"
3426 "Default string\n")
3427{
3428 host.motd = default_motd;
3429 return CMD_SUCCESS;
3430}
3431
3432DEFUN (no_banner_motd,
3433 no_banner_motd_cmd,
3434 "no banner motd",
3435 NO_STR
3436 "Set banner string\n"
3437 "Strings for motd\n")
3438{
3439 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003440 if (host.motdfile)
3441 XFREE (MTYPE_TMP, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003442 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003443 return CMD_SUCCESS;
3444}
3445
3446/* Set config filename. Called from vty.c */
3447void
3448host_config_set (char *filename)
3449{
3450 host.config = strdup (filename);
3451}
3452
3453void
3454install_default (enum node_type node)
3455{
3456 install_element (node, &config_exit_cmd);
3457 install_element (node, &config_quit_cmd);
3458 install_element (node, &config_end_cmd);
3459 install_element (node, &config_help_cmd);
3460 install_element (node, &config_list_cmd);
3461
3462 install_element (node, &config_write_terminal_cmd);
3463 install_element (node, &config_write_file_cmd);
3464 install_element (node, &config_write_memory_cmd);
3465 install_element (node, &config_write_cmd);
3466 install_element (node, &show_running_config_cmd);
3467}
3468
3469/* Initialize command interface. Install basic nodes and commands. */
3470void
3471cmd_init (int terminal)
3472{
3473 /* Allocate initial top vector of commands. */
3474 cmdvec = vector_init (VECTOR_MIN_SIZE);
3475
3476 /* Default host value settings. */
3477 host.name = NULL;
3478 host.password = NULL;
3479 host.enable = NULL;
3480 host.logfile = NULL;
3481 host.config = NULL;
3482 host.lines = -1;
3483 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003484 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003485
3486 /* Install top nodes. */
3487 install_node (&view_node, NULL);
3488 install_node (&enable_node, NULL);
3489 install_node (&auth_node, NULL);
3490 install_node (&auth_enable_node, NULL);
3491 install_node (&config_node, config_write_host);
3492
3493 /* Each node's basic commands. */
3494 install_element (VIEW_NODE, &show_version_cmd);
3495 if (terminal)
3496 {
3497 install_element (VIEW_NODE, &config_list_cmd);
3498 install_element (VIEW_NODE, &config_exit_cmd);
3499 install_element (VIEW_NODE, &config_quit_cmd);
3500 install_element (VIEW_NODE, &config_help_cmd);
3501 install_element (VIEW_NODE, &config_enable_cmd);
3502 install_element (VIEW_NODE, &config_terminal_length_cmd);
3503 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003504 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003505 install_element (VIEW_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003506 }
3507
3508 if (terminal)
3509 {
3510 install_default (ENABLE_NODE);
3511 install_element (ENABLE_NODE, &config_disable_cmd);
3512 install_element (ENABLE_NODE, &config_terminal_cmd);
3513 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3514 }
3515 install_element (ENABLE_NODE, &show_startup_config_cmd);
3516 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003517
3518 if (terminal)
paul718e3742002-12-13 20:15:29 +00003519 {
hassoe7168df2004-10-03 20:11:32 +00003520 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3521 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003522 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003523 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003524 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003525
3526 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003527 }
3528
3529 install_element (CONFIG_NODE, &hostname_cmd);
3530 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003531
hassoea8e9d92004-10-07 21:32:14 +00003532 if (terminal)
3533 {
hassoe7168df2004-10-03 20:11:32 +00003534 install_element (CONFIG_NODE, &password_cmd);
3535 install_element (CONFIG_NODE, &password_text_cmd);
3536 install_element (CONFIG_NODE, &enable_password_cmd);
3537 install_element (CONFIG_NODE, &enable_password_text_cmd);
3538 install_element (CONFIG_NODE, &no_enable_password_cmd);
3539
paul718e3742002-12-13 20:15:29 +00003540 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003541 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003542 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003543 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3544 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3545 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003546 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003547 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003548 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003549 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003550 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003551 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003552 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003554 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003555 install_element (CONFIG_NODE, &config_log_facility_cmd);
3556 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003557 install_element (CONFIG_NODE, &config_log_trap_cmd);
3558 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3559 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3560 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
3561 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3562 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3563 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003564 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003565 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3566 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3567 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003568
paul9ab68122003-01-18 01:16:20 +00003569 install_element(VIEW_NODE, &show_thread_cpu_cmd);
3570 install_element(ENABLE_NODE, &show_thread_cpu_cmd);
3571 }
paul718e3742002-12-13 20:15:29 +00003572 srand(time(NULL));
3573}