blob: e62a7a7e6ec8f30594af07aa73a2be3f8fb98e0d [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
ajs274a4a42004-12-07 15:39:31 +00002 Command interpreter routine for virtual terminal [aka TeletYpe]
paul718e3742002-12-13 20:15:29 +00003 Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4
5This file is part of GNU Zebra.
6
7GNU Zebra is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation; either version 2, or (at your
10option) any later version.
11
12GNU Zebra is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Zebra; see the file COPYING. If not, write to the
19Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
22#include <zebra.h>
23
paulb21b19c2003-06-15 01:28:29 +000024
paul718e3742002-12-13 20:15:29 +000025#include "memory.h"
26#include "log.h"
gdt5e4fa162004-03-16 14:38:36 +000027#include <lib/version.h>
paul9ab68122003-01-18 01:16:20 +000028#include "thread.h"
paulb21b19c2003-06-15 01:28:29 +000029#include "vector.h"
30#include "vty.h"
31#include "command.h"
paul354d1192005-04-25 16:26:42 +000032#include "workqueue.h"
paul718e3742002-12-13 20:15:29 +000033
34/* Command vector which includes some level of command lists. Normally
35 each daemon maintains each own cmdvec. */
pauleb820af2005-09-05 11:54:13 +000036vector cmdvec = NULL;
paul718e3742002-12-13 20:15:29 +000037
Chris Caputo228da422009-07-18 05:44:03 +000038struct desc desc_cr;
39char *command_cr = NULL;
40
paul718e3742002-12-13 20:15:29 +000041/* Host information structure. */
42struct host host;
43
paul718e3742002-12-13 20:15:29 +000044/* Standard command node structures. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080045static struct cmd_node auth_node =
paul718e3742002-12-13 20:15:29 +000046{
47 AUTH_NODE,
48 "Password: ",
49};
50
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080051static struct cmd_node view_node =
paul718e3742002-12-13 20:15:29 +000052{
53 VIEW_NODE,
54 "%s> ",
55};
56
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080057static struct cmd_node restricted_node =
Paul Jakma62687ff2008-08-23 14:27:06 +010058{
59 RESTRICTED_NODE,
60 "%s$ ",
61};
62
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080063static struct cmd_node auth_enable_node =
paul718e3742002-12-13 20:15:29 +000064{
65 AUTH_ENABLE_NODE,
66 "Password: ",
67};
68
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080069static struct cmd_node enable_node =
paul718e3742002-12-13 20:15:29 +000070{
71 ENABLE_NODE,
72 "%s# ",
73};
74
Stephen Hemminger7fc626d2008-12-01 11:10:34 -080075static struct cmd_node config_node =
paul718e3742002-12-13 20:15:29 +000076{
77 CONFIG_NODE,
78 "%s(config)# ",
79 1
80};
hasso6590f2c2004-10-19 20:40:08 +000081
82/* Default motd string. */
Stephen Hemminger2d362d12009-12-21 12:54:58 +030083static const char *default_motd =
hasso6590f2c2004-10-19 20:40:08 +000084"\r\n\
85Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
86" QUAGGA_COPYRIGHT "\r\n\
87\r\n";
88
ajs274a4a42004-12-07 15:39:31 +000089
Stephen Hemminger2d362d12009-12-21 12:54:58 +030090static const struct facility_map {
ajs274a4a42004-12-07 15:39:31 +000091 int facility;
92 const char *name;
93 size_t match;
94} syslog_facilities[] =
95 {
96 { LOG_KERN, "kern", 1 },
97 { LOG_USER, "user", 2 },
98 { LOG_MAIL, "mail", 1 },
99 { LOG_DAEMON, "daemon", 1 },
100 { LOG_AUTH, "auth", 1 },
101 { LOG_SYSLOG, "syslog", 1 },
102 { LOG_LPR, "lpr", 2 },
103 { LOG_NEWS, "news", 1 },
104 { LOG_UUCP, "uucp", 2 },
105 { LOG_CRON, "cron", 1 },
106#ifdef LOG_FTP
107 { LOG_FTP, "ftp", 1 },
108#endif
109 { LOG_LOCAL0, "local0", 6 },
110 { LOG_LOCAL1, "local1", 6 },
111 { LOG_LOCAL2, "local2", 6 },
112 { LOG_LOCAL3, "local3", 6 },
113 { LOG_LOCAL4, "local4", 6 },
114 { LOG_LOCAL5, "local5", 6 },
115 { LOG_LOCAL6, "local6", 6 },
116 { LOG_LOCAL7, "local7", 6 },
117 { 0, NULL, 0 },
118 };
119
120static const char *
121facility_name(int facility)
122{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300123 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000124
125 for (fm = syslog_facilities; fm->name; fm++)
126 if (fm->facility == facility)
127 return fm->name;
128 return "";
129}
130
131static int
132facility_match(const char *str)
133{
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300134 const struct facility_map *fm;
ajs274a4a42004-12-07 15:39:31 +0000135
136 for (fm = syslog_facilities; fm->name; fm++)
137 if (!strncmp(str,fm->name,fm->match))
138 return fm->facility;
139 return -1;
140}
141
142static int
143level_match(const char *s)
144{
145 int level ;
146
147 for ( level = 0 ; zlog_priority [level] != NULL ; level ++ )
148 if (!strncmp (s, zlog_priority[level], 2))
149 return level;
150 return ZLOG_DISABLED;
151}
152
ajscb585b62005-01-14 17:09:38 +0000153/* This is called from main when a daemon is invoked with -v or --version. */
hasso6590f2c2004-10-19 20:40:08 +0000154void
155print_version (const char *progname)
156{
ajscb585b62005-01-14 17:09:38 +0000157 printf ("%s version %s\n", progname, QUAGGA_VERSION);
158 printf ("%s\n", QUAGGA_COPYRIGHT);
hasso6590f2c2004-10-19 20:40:08 +0000159}
160
paul718e3742002-12-13 20:15:29 +0000161
162/* Utility function to concatenate argv argument into a single string
163 with inserting ' ' character between each argument. */
164char *
paul42d49862004-10-13 05:22:18 +0000165argv_concat (const char **argv, int argc, int shift)
paul718e3742002-12-13 20:15:29 +0000166{
167 int i;
ajsf6834d42005-01-28 20:28:35 +0000168 size_t len;
paul718e3742002-12-13 20:15:29 +0000169 char *str;
ajsf6834d42005-01-28 20:28:35 +0000170 char *p;
paul718e3742002-12-13 20:15:29 +0000171
ajsf6834d42005-01-28 20:28:35 +0000172 len = 0;
173 for (i = shift; i < argc; i++)
174 len += strlen(argv[i])+1;
175 if (!len)
176 return NULL;
177 p = str = XMALLOC(MTYPE_TMP, len);
paul718e3742002-12-13 20:15:29 +0000178 for (i = shift; i < argc; i++)
179 {
ajsf6834d42005-01-28 20:28:35 +0000180 size_t arglen;
181 memcpy(p, argv[i], (arglen = strlen(argv[i])));
182 p += arglen;
183 *p++ = ' ';
paul718e3742002-12-13 20:15:29 +0000184 }
ajsf6834d42005-01-28 20:28:35 +0000185 *(p-1) = '\0';
paul718e3742002-12-13 20:15:29 +0000186 return str;
187}
188
189/* Install top node of command vector. */
190void
191install_node (struct cmd_node *node,
192 int (*func) (struct vty *))
193{
194 vector_set_index (cmdvec, node->node, node);
195 node->func = func;
196 node->cmd_vector = vector_init (VECTOR_MIN_SIZE);
197}
198
199/* Compare two command's string. Used in sort_node (). */
ajs274a4a42004-12-07 15:39:31 +0000200static int
paul718e3742002-12-13 20:15:29 +0000201cmp_node (const void *p, const void *q)
202{
Chris Caputo228da422009-07-18 05:44:03 +0000203 const struct cmd_element *a = *(struct cmd_element * const *)p;
204 const struct cmd_element *b = *(struct cmd_element * const *)q;
paul718e3742002-12-13 20:15:29 +0000205
206 return strcmp (a->string, b->string);
207}
208
ajs274a4a42004-12-07 15:39:31 +0000209static int
paul718e3742002-12-13 20:15:29 +0000210cmp_desc (const void *p, const void *q)
211{
Chris Caputo228da422009-07-18 05:44:03 +0000212 const struct desc *a = *(struct desc * const *)p;
213 const struct desc *b = *(struct desc * const *)q;
paul718e3742002-12-13 20:15:29 +0000214
215 return strcmp (a->cmd, b->cmd);
216}
217
218/* Sort each node's command element according to command string. */
219void
220sort_node ()
221{
hasso8c328f12004-10-05 21:01:23 +0000222 unsigned int i, j;
paul718e3742002-12-13 20:15:29 +0000223 struct cmd_node *cnode;
224 vector descvec;
225 struct cmd_element *cmd_element;
226
Chris Caputo228da422009-07-18 05:44:03 +0000227 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +0000228 if ((cnode = vector_slot (cmdvec, i)) != NULL)
229 {
230 vector cmd_vector = cnode->cmd_vector;
paul55468c82005-03-14 20:19:01 +0000231 qsort (cmd_vector->index, vector_active (cmd_vector),
paulb8961472005-03-14 17:35:52 +0000232 sizeof (void *), cmp_node);
paul718e3742002-12-13 20:15:29 +0000233
paul55468c82005-03-14 20:19:01 +0000234 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +0000235 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +0000236 && vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +0000237 {
238 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +0000239 vector_active (cmd_element->strvec) - 1);
240 qsort (descvec->index, vector_active (descvec),
paulb8961472005-03-14 17:35:52 +0000241 sizeof (void *), cmp_desc);
paul718e3742002-12-13 20:15:29 +0000242 }
243 }
244}
245
246/* Breaking up string into each command piece. I assume given
247 character is separated by a space character. Return value is a
248 vector which includes char ** data element. */
249vector
hassoea8e9d92004-10-07 21:32:14 +0000250cmd_make_strvec (const char *string)
paul718e3742002-12-13 20:15:29 +0000251{
hassoea8e9d92004-10-07 21:32:14 +0000252 const char *cp, *start;
253 char *token;
paul718e3742002-12-13 20:15:29 +0000254 int strlen;
255 vector strvec;
256
257 if (string == NULL)
258 return NULL;
259
260 cp = string;
261
262 /* Skip white spaces. */
263 while (isspace ((int) *cp) && *cp != '\0')
264 cp++;
265
266 /* Return if there is only white spaces */
267 if (*cp == '\0')
268 return NULL;
269
270 if (*cp == '!' || *cp == '#')
271 return NULL;
272
273 /* Prepare return vector. */
274 strvec = vector_init (VECTOR_MIN_SIZE);
275
276 /* Copy each command piece and set into vector. */
277 while (1)
278 {
279 start = cp;
280 while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') &&
281 *cp != '\0')
282 cp++;
283 strlen = cp - start;
284 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
285 memcpy (token, start, strlen);
286 *(token + strlen) = '\0';
287 vector_set (strvec, token);
288
289 while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') &&
290 *cp != '\0')
291 cp++;
292
293 if (*cp == '\0')
294 return strvec;
295 }
296}
297
298/* Free allocated string vector. */
299void
300cmd_free_strvec (vector v)
301{
hasso8c328f12004-10-05 21:01:23 +0000302 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000303 char *cp;
304
305 if (!v)
306 return;
307
paul55468c82005-03-14 20:19:01 +0000308 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +0000309 if ((cp = vector_slot (v, i)) != NULL)
310 XFREE (MTYPE_STRVEC, cp);
311
312 vector_free (v);
313}
314
315/* Fetch next description. Used in cmd_make_descvec(). */
ajs274a4a42004-12-07 15:39:31 +0000316static char *
hasso6ad96ea2004-10-07 19:33:46 +0000317cmd_desc_str (const char **string)
paul718e3742002-12-13 20:15:29 +0000318{
hasso6ad96ea2004-10-07 19:33:46 +0000319 const char *cp, *start;
320 char *token;
paul718e3742002-12-13 20:15:29 +0000321 int strlen;
322
323 cp = *string;
324
325 if (cp == NULL)
326 return NULL;
327
328 /* Skip white spaces. */
329 while (isspace ((int) *cp) && *cp != '\0')
330 cp++;
331
332 /* Return if there is only white spaces */
333 if (*cp == '\0')
334 return NULL;
335
336 start = cp;
337
338 while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
339 cp++;
340
341 strlen = cp - start;
342 token = XMALLOC (MTYPE_STRVEC, strlen + 1);
343 memcpy (token, start, strlen);
344 *(token + strlen) = '\0';
345
346 *string = cp;
347
348 return token;
349}
350
351/* New string vector. */
ajs274a4a42004-12-07 15:39:31 +0000352static vector
hasso8c328f12004-10-05 21:01:23 +0000353cmd_make_descvec (const char *string, const char *descstr)
paul718e3742002-12-13 20:15:29 +0000354{
355 int multiple = 0;
hasso8c328f12004-10-05 21:01:23 +0000356 const char *sp;
paul718e3742002-12-13 20:15:29 +0000357 char *token;
358 int len;
hasso8c328f12004-10-05 21:01:23 +0000359 const char *cp;
360 const char *dp;
paul718e3742002-12-13 20:15:29 +0000361 vector allvec;
362 vector strvec = NULL;
363 struct desc *desc;
364
365 cp = string;
366 dp = descstr;
367
368 if (cp == NULL)
369 return NULL;
370
371 allvec = vector_init (VECTOR_MIN_SIZE);
372
373 while (1)
374 {
375 while (isspace ((int) *cp) && *cp != '\0')
376 cp++;
377
378 if (*cp == '(')
379 {
380 multiple = 1;
381 cp++;
382 }
383 if (*cp == ')')
384 {
385 multiple = 0;
386 cp++;
387 }
388 if (*cp == '|')
389 {
390 if (! multiple)
391 {
392 fprintf (stderr, "Command parse error!: %s\n", string);
393 exit (1);
394 }
395 cp++;
396 }
397
398 while (isspace ((int) *cp) && *cp != '\0')
399 cp++;
400
401 if (*cp == '(')
402 {
403 multiple = 1;
404 cp++;
405 }
406
407 if (*cp == '\0')
408 return allvec;
409
410 sp = cp;
411
412 while (! (isspace ((int) *cp) || *cp == '\r' || *cp == '\n' || *cp == ')' || *cp == '|') && *cp != '\0')
413 cp++;
414
415 len = cp - sp;
416
417 token = XMALLOC (MTYPE_STRVEC, len + 1);
418 memcpy (token, sp, len);
419 *(token + len) = '\0';
420
421 desc = XCALLOC (MTYPE_DESC, sizeof (struct desc));
422 desc->cmd = token;
423 desc->str = cmd_desc_str (&dp);
424
425 if (multiple)
426 {
427 if (multiple == 1)
428 {
429 strvec = vector_init (VECTOR_MIN_SIZE);
430 vector_set (allvec, strvec);
431 }
432 multiple++;
433 }
434 else
435 {
436 strvec = vector_init (VECTOR_MIN_SIZE);
437 vector_set (allvec, strvec);
438 }
439 vector_set (strvec, desc);
440 }
441}
442
443/* Count mandantory string vector size. This is to determine inputed
444 command has enough command length. */
ajs274a4a42004-12-07 15:39:31 +0000445static int
paul718e3742002-12-13 20:15:29 +0000446cmd_cmdsize (vector strvec)
447{
hasso8c328f12004-10-05 21:01:23 +0000448 unsigned int i;
paul718e3742002-12-13 20:15:29 +0000449 int size = 0;
450 vector descvec;
paulb8961472005-03-14 17:35:52 +0000451 struct desc *desc;
paul718e3742002-12-13 20:15:29 +0000452
paul55468c82005-03-14 20:19:01 +0000453 for (i = 0; i < vector_active (strvec); i++)
paulb8961472005-03-14 17:35:52 +0000454 if ((descvec = vector_slot (strvec, i)) != NULL)
paul718e3742002-12-13 20:15:29 +0000455 {
paul55468c82005-03-14 20:19:01 +0000456 if ((vector_active (descvec)) == 1
paulb8961472005-03-14 17:35:52 +0000457 && (desc = vector_slot (descvec, 0)) != NULL)
paul718e3742002-12-13 20:15:29 +0000458 {
hasso8c328f12004-10-05 21:01:23 +0000459 if (desc->cmd == NULL || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +0000460 return size;
461 else
462 size++;
463 }
464 else
465 size++;
466 }
467 return size;
468}
469
470/* Return prompt character of specified node. */
hasso8c328f12004-10-05 21:01:23 +0000471const char *
paul718e3742002-12-13 20:15:29 +0000472cmd_prompt (enum node_type node)
473{
474 struct cmd_node *cnode;
475
476 cnode = vector_slot (cmdvec, node);
477 return cnode->prompt;
478}
479
480/* Install a command into a node. */
481void
482install_element (enum node_type ntype, struct cmd_element *cmd)
483{
484 struct cmd_node *cnode;
pauleb820af2005-09-05 11:54:13 +0000485
486 /* cmd_init hasn't been called */
487 if (!cmdvec)
488 return;
489
paul718e3742002-12-13 20:15:29 +0000490 cnode = vector_slot (cmdvec, ntype);
491
492 if (cnode == NULL)
493 {
494 fprintf (stderr, "Command node %d doesn't exist, please check it\n",
495 ntype);
496 exit (1);
497 }
498
499 vector_set (cnode->cmd_vector, cmd);
500
Chris Caputo228da422009-07-18 05:44:03 +0000501 if (cmd->strvec == NULL)
502 cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);
503
paul718e3742002-12-13 20:15:29 +0000504 cmd->cmdsize = cmd_cmdsize (cmd->strvec);
505}
506
Stephen Hemminger2d362d12009-12-21 12:54:58 +0300507static const unsigned char itoa64[] =
paul718e3742002-12-13 20:15:29 +0000508"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
509
ajs274a4a42004-12-07 15:39:31 +0000510static void
paul718e3742002-12-13 20:15:29 +0000511to64(char *s, long v, int n)
512{
513 while (--n >= 0)
514 {
515 *s++ = itoa64[v&0x3f];
516 v >>= 6;
517 }
518}
519
ajs274a4a42004-12-07 15:39:31 +0000520static char *
521zencrypt (const char *passwd)
paul718e3742002-12-13 20:15:29 +0000522{
523 char salt[6];
524 struct timeval tv;
525 char *crypt (const char *, const char *);
526
527 gettimeofday(&tv,0);
528
529 to64(&salt[0], random(), 3);
530 to64(&salt[3], tv.tv_usec, 3);
531 salt[5] = '\0';
532
533 return crypt (passwd, salt);
534}
535
536/* This function write configuration of this host. */
ajs274a4a42004-12-07 15:39:31 +0000537static int
paul718e3742002-12-13 20:15:29 +0000538config_write_host (struct vty *vty)
539{
540 if (host.name)
541 vty_out (vty, "hostname %s%s", host.name, VTY_NEWLINE);
542
543 if (host.encrypt)
544 {
545 if (host.password_encrypt)
546 vty_out (vty, "password 8 %s%s", host.password_encrypt, VTY_NEWLINE);
547 if (host.enable_encrypt)
548 vty_out (vty, "enable password 8 %s%s", host.enable_encrypt, VTY_NEWLINE);
549 }
550 else
551 {
552 if (host.password)
553 vty_out (vty, "password %s%s", host.password, VTY_NEWLINE);
554 if (host.enable)
555 vty_out (vty, "enable password %s%s", host.enable, VTY_NEWLINE);
556 }
557
ajs274a4a42004-12-07 15:39:31 +0000558 if (zlog_default->default_lvl != LOG_DEBUG)
ajs82146b82004-12-07 17:15:55 +0000559 {
560 vty_out (vty, "! N.B. The 'log trap' command is deprecated.%s",
561 VTY_NEWLINE);
562 vty_out (vty, "log trap %s%s",
563 zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
564 }
paul718e3742002-12-13 20:15:29 +0000565
ajs274a4a42004-12-07 15:39:31 +0000566 if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED))
paul12ab19f2003-07-26 06:14:55 +0000567 {
ajs274a4a42004-12-07 15:39:31 +0000568 vty_out (vty, "log file %s", host.logfile);
569 if (zlog_default->maxlvl[ZLOG_DEST_FILE] != zlog_default->default_lvl)
570 vty_out (vty, " %s",
571 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_FILE]]);
paul12ab19f2003-07-26 06:14:55 +0000572 vty_out (vty, "%s", VTY_NEWLINE);
573 }
ajs274a4a42004-12-07 15:39:31 +0000574
575 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED)
576 {
577 vty_out (vty, "log stdout");
578 if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != zlog_default->default_lvl)
579 vty_out (vty, " %s",
580 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_STDOUT]]);
581 vty_out (vty, "%s", VTY_NEWLINE);
582 }
583
584 if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
585 vty_out(vty,"no log monitor%s",VTY_NEWLINE);
586 else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] != zlog_default->default_lvl)
587 vty_out(vty,"log monitor %s%s",
588 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],VTY_NEWLINE);
589
590 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED)
591 {
592 vty_out (vty, "log syslog");
593 if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != zlog_default->default_lvl)
594 vty_out (vty, " %s",
595 zlog_priority[zlog_default->maxlvl[ZLOG_DEST_SYSLOG]]);
596 vty_out (vty, "%s", VTY_NEWLINE);
597 }
598
599 if (zlog_default->facility != LOG_DAEMON)
600 vty_out (vty, "log facility %s%s",
601 facility_name(zlog_default->facility), VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000602
603 if (zlog_default->record_priority == 1)
604 vty_out (vty, "log record-priority%s", VTY_NEWLINE);
605
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000606 if (zlog_default->timestamp_precision > 0)
607 vty_out (vty, "log timestamp precision %d%s",
608 zlog_default->timestamp_precision, VTY_NEWLINE);
609
paul718e3742002-12-13 20:15:29 +0000610 if (host.advanced)
611 vty_out (vty, "service advanced-vty%s", VTY_NEWLINE);
612
613 if (host.encrypt)
614 vty_out (vty, "service password-encryption%s", VTY_NEWLINE);
615
616 if (host.lines >= 0)
617 vty_out (vty, "service terminal-length %d%s", host.lines,
618 VTY_NEWLINE);
619
paul3b0c5d92005-03-08 10:43:43 +0000620 if (host.motdfile)
621 vty_out (vty, "banner motd file %s%s", host.motdfile, VTY_NEWLINE);
622 else if (! host.motd)
paul718e3742002-12-13 20:15:29 +0000623 vty_out (vty, "no banner motd%s", VTY_NEWLINE);
624
625 return 1;
626}
627
628/* Utility function for getting command vector. */
ajs274a4a42004-12-07 15:39:31 +0000629static vector
paul718e3742002-12-13 20:15:29 +0000630cmd_node_vector (vector v, enum node_type ntype)
631{
632 struct cmd_node *cnode = vector_slot (v, ntype);
633 return cnode->cmd_vector;
634}
635
ajs274a4a42004-12-07 15:39:31 +0000636#if 0
637/* Filter command vector by symbol. This function is not actually used;
638 * should it be deleted? */
639static int
paul718e3742002-12-13 20:15:29 +0000640cmd_filter_by_symbol (char *command, char *symbol)
641{
642 int i, lim;
643
644 if (strcmp (symbol, "IPV4_ADDRESS") == 0)
645 {
646 i = 0;
647 lim = strlen (command);
648 while (i < lim)
649 {
650 if (! (isdigit ((int) command[i]) || command[i] == '.' || command[i] == '/'))
651 return 1;
652 i++;
653 }
654 return 0;
655 }
656 if (strcmp (symbol, "STRING") == 0)
657 {
658 i = 0;
659 lim = strlen (command);
660 while (i < lim)
661 {
662 if (! (isalpha ((int) command[i]) || command[i] == '_' || command[i] == '-'))
663 return 1;
664 i++;
665 }
666 return 0;
667 }
668 if (strcmp (symbol, "IFNAME") == 0)
669 {
670 i = 0;
671 lim = strlen (command);
672 while (i < lim)
673 {
674 if (! isalnum ((int) command[i]))
675 return 1;
676 i++;
677 }
678 return 0;
679 }
680 return 0;
681}
ajs274a4a42004-12-07 15:39:31 +0000682#endif
paul718e3742002-12-13 20:15:29 +0000683
684/* Completion match types. */
685enum match_type
686{
687 no_match,
688 extend_match,
689 ipv4_prefix_match,
690 ipv4_match,
691 ipv6_prefix_match,
692 ipv6_match,
693 range_match,
694 vararg_match,
695 partly_match,
696 exact_match
697};
698
ajs274a4a42004-12-07 15:39:31 +0000699static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000700cmd_ipv4_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000701{
hasso8c328f12004-10-05 21:01:23 +0000702 const char *sp;
paul718e3742002-12-13 20:15:29 +0000703 int dots = 0, nums = 0;
704 char buf[4];
705
706 if (str == NULL)
707 return partly_match;
708
709 for (;;)
710 {
711 memset (buf, 0, sizeof (buf));
712 sp = str;
713 while (*str != '\0')
714 {
715 if (*str == '.')
716 {
717 if (dots >= 3)
718 return no_match;
719
720 if (*(str + 1) == '.')
721 return no_match;
722
723 if (*(str + 1) == '\0')
724 return partly_match;
725
726 dots++;
727 break;
728 }
729 if (!isdigit ((int) *str))
730 return no_match;
731
732 str++;
733 }
734
735 if (str - sp > 3)
736 return no_match;
737
738 strncpy (buf, sp, str - sp);
739 if (atoi (buf) > 255)
740 return no_match;
741
742 nums++;
743
744 if (*str == '\0')
745 break;
746
747 str++;
748 }
749
750 if (nums < 4)
751 return partly_match;
752
753 return exact_match;
754}
755
ajs274a4a42004-12-07 15:39:31 +0000756static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000757cmd_ipv4_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000758{
hasso8c328f12004-10-05 21:01:23 +0000759 const char *sp;
paul718e3742002-12-13 20:15:29 +0000760 int dots = 0;
761 char buf[4];
762
763 if (str == NULL)
764 return partly_match;
765
766 for (;;)
767 {
768 memset (buf, 0, sizeof (buf));
769 sp = str;
770 while (*str != '\0' && *str != '/')
771 {
772 if (*str == '.')
773 {
774 if (dots == 3)
775 return no_match;
776
777 if (*(str + 1) == '.' || *(str + 1) == '/')
778 return no_match;
779
780 if (*(str + 1) == '\0')
781 return partly_match;
782
783 dots++;
784 break;
785 }
786
787 if (!isdigit ((int) *str))
788 return no_match;
789
790 str++;
791 }
792
793 if (str - sp > 3)
794 return no_match;
795
796 strncpy (buf, sp, str - sp);
797 if (atoi (buf) > 255)
798 return no_match;
799
800 if (dots == 3)
801 {
802 if (*str == '/')
803 {
804 if (*(str + 1) == '\0')
805 return partly_match;
806
807 str++;
808 break;
809 }
810 else if (*str == '\0')
811 return partly_match;
812 }
813
814 if (*str == '\0')
815 return partly_match;
816
817 str++;
818 }
819
820 sp = str;
821 while (*str != '\0')
822 {
823 if (!isdigit ((int) *str))
824 return no_match;
825
826 str++;
827 }
828
829 if (atoi (sp) > 32)
830 return no_match;
831
832 return exact_match;
833}
834
835#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
836#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
837#define STATE_START 1
838#define STATE_COLON 2
839#define STATE_DOUBLE 3
840#define STATE_ADDR 4
841#define STATE_DOT 5
842#define STATE_SLASH 6
843#define STATE_MASK 7
844
paul22e0a9e2003-07-11 17:55:46 +0000845#ifdef HAVE_IPV6
846
ajs274a4a42004-12-07 15:39:31 +0000847static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000848cmd_ipv6_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000849{
850 int state = STATE_START;
851 int colons = 0, nums = 0, double_colon = 0;
hasso8c328f12004-10-05 21:01:23 +0000852 const char *sp = NULL;
hasso726f9b22003-05-25 21:04:54 +0000853 struct sockaddr_in6 sin6_dummy;
854 int ret;
paul718e3742002-12-13 20:15:29 +0000855
856 if (str == NULL)
857 return partly_match;
858
859 if (strspn (str, IPV6_ADDR_STR) != strlen (str))
860 return no_match;
861
hasso726f9b22003-05-25 21:04:54 +0000862 /* use inet_pton that has a better support,
863 * for example inet_pton can support the automatic addresses:
864 * ::1.2.3.4
865 */
866 ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
867
868 if (ret == 1)
869 return exact_match;
870
paul718e3742002-12-13 20:15:29 +0000871 while (*str != '\0')
872 {
873 switch (state)
874 {
875 case STATE_START:
876 if (*str == ':')
877 {
878 if (*(str + 1) != ':' && *(str + 1) != '\0')
879 return no_match;
880 colons--;
881 state = STATE_COLON;
882 }
883 else
884 {
885 sp = str;
886 state = STATE_ADDR;
887 }
888
889 continue;
890 case STATE_COLON:
891 colons++;
892 if (*(str + 1) == ':')
893 state = STATE_DOUBLE;
894 else
895 {
896 sp = str + 1;
897 state = STATE_ADDR;
898 }
899 break;
900 case STATE_DOUBLE:
901 if (double_colon)
902 return no_match;
903
904 if (*(str + 1) == ':')
905 return no_match;
906 else
907 {
908 if (*(str + 1) != '\0')
909 colons++;
910 sp = str + 1;
911 state = STATE_ADDR;
912 }
913
914 double_colon++;
915 nums++;
916 break;
917 case STATE_ADDR:
918 if (*(str + 1) == ':' || *(str + 1) == '\0')
919 {
920 if (str - sp > 3)
921 return no_match;
922
923 nums++;
924 state = STATE_COLON;
925 }
926 if (*(str + 1) == '.')
927 state = STATE_DOT;
928 break;
929 case STATE_DOT:
930 state = STATE_ADDR;
931 break;
932 default:
933 break;
934 }
935
936 if (nums > 8)
937 return no_match;
938
939 if (colons > 7)
940 return no_match;
941
942 str++;
943 }
944
945#if 0
946 if (nums < 11)
947 return partly_match;
948#endif /* 0 */
949
950 return exact_match;
951}
952
ajs274a4a42004-12-07 15:39:31 +0000953static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000954cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000955{
956 int state = STATE_START;
957 int colons = 0, nums = 0, double_colon = 0;
958 int mask;
hasso8c328f12004-10-05 21:01:23 +0000959 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000960 char *endptr = NULL;
961
962 if (str == NULL)
963 return partly_match;
964
965 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
966 return no_match;
967
968 while (*str != '\0' && state != STATE_MASK)
969 {
970 switch (state)
971 {
972 case STATE_START:
973 if (*str == ':')
974 {
975 if (*(str + 1) != ':' && *(str + 1) != '\0')
976 return no_match;
977 colons--;
978 state = STATE_COLON;
979 }
980 else
981 {
982 sp = str;
983 state = STATE_ADDR;
984 }
985
986 continue;
987 case STATE_COLON:
988 colons++;
989 if (*(str + 1) == '/')
990 return no_match;
991 else if (*(str + 1) == ':')
992 state = STATE_DOUBLE;
993 else
994 {
995 sp = str + 1;
996 state = STATE_ADDR;
997 }
998 break;
999 case STATE_DOUBLE:
1000 if (double_colon)
1001 return no_match;
1002
1003 if (*(str + 1) == ':')
1004 return no_match;
1005 else
1006 {
1007 if (*(str + 1) != '\0' && *(str + 1) != '/')
1008 colons++;
1009 sp = str + 1;
1010
1011 if (*(str + 1) == '/')
1012 state = STATE_SLASH;
1013 else
1014 state = STATE_ADDR;
1015 }
1016
1017 double_colon++;
1018 nums += 1;
1019 break;
1020 case STATE_ADDR:
1021 if (*(str + 1) == ':' || *(str + 1) == '.'
1022 || *(str + 1) == '\0' || *(str + 1) == '/')
1023 {
1024 if (str - sp > 3)
1025 return no_match;
1026
1027 for (; sp <= str; sp++)
1028 if (*sp == '/')
1029 return no_match;
1030
1031 nums++;
1032
1033 if (*(str + 1) == ':')
1034 state = STATE_COLON;
1035 else if (*(str + 1) == '.')
1036 state = STATE_DOT;
1037 else if (*(str + 1) == '/')
1038 state = STATE_SLASH;
1039 }
1040 break;
1041 case STATE_DOT:
1042 state = STATE_ADDR;
1043 break;
1044 case STATE_SLASH:
1045 if (*(str + 1) == '\0')
1046 return partly_match;
1047
1048 state = STATE_MASK;
1049 break;
1050 default:
1051 break;
1052 }
1053
1054 if (nums > 11)
1055 return no_match;
1056
1057 if (colons > 7)
1058 return no_match;
1059
1060 str++;
1061 }
1062
1063 if (state < STATE_MASK)
1064 return partly_match;
1065
1066 mask = strtol (str, &endptr, 10);
1067 if (*endptr != '\0')
1068 return no_match;
1069
1070 if (mask < 0 || mask > 128)
1071 return no_match;
1072
1073/* I don't know why mask < 13 makes command match partly.
1074 Forgive me to make this comments. I Want to set static default route
1075 because of lack of function to originate default in ospf6d; sorry
1076 yasu
1077 if (mask < 13)
1078 return partly_match;
1079*/
1080
1081 return exact_match;
1082}
1083
paul22e0a9e2003-07-11 17:55:46 +00001084#endif /* HAVE_IPV6 */
1085
paul718e3742002-12-13 20:15:29 +00001086#define DECIMAL_STRLEN_MAX 10
1087
ajs274a4a42004-12-07 15:39:31 +00001088static int
hasso8c328f12004-10-05 21:01:23 +00001089cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001090{
1091 char *p;
1092 char buf[DECIMAL_STRLEN_MAX + 1];
1093 char *endptr = NULL;
1094 unsigned long min, max, val;
1095
1096 if (str == NULL)
1097 return 1;
1098
1099 val = strtoul (str, &endptr, 10);
1100 if (*endptr != '\0')
1101 return 0;
1102
1103 range++;
1104 p = strchr (range, '-');
1105 if (p == NULL)
1106 return 0;
1107 if (p - range > DECIMAL_STRLEN_MAX)
1108 return 0;
1109 strncpy (buf, range, p - range);
1110 buf[p - range] = '\0';
1111 min = strtoul (buf, &endptr, 10);
1112 if (*endptr != '\0')
1113 return 0;
1114
1115 range = p + 1;
1116 p = strchr (range, '>');
1117 if (p == NULL)
1118 return 0;
1119 if (p - range > DECIMAL_STRLEN_MAX)
1120 return 0;
1121 strncpy (buf, range, p - range);
1122 buf[p - range] = '\0';
1123 max = strtoul (buf, &endptr, 10);
1124 if (*endptr != '\0')
1125 return 0;
1126
1127 if (val < min || val > max)
1128 return 0;
1129
1130 return 1;
1131}
1132
1133/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001134static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001135cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001136{
hasso8c328f12004-10-05 21:01:23 +00001137 unsigned int i;
1138 const char *str;
paul718e3742002-12-13 20:15:29 +00001139 struct cmd_element *cmd_element;
1140 enum match_type match_type;
1141 vector descvec;
1142 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001143
paul718e3742002-12-13 20:15:29 +00001144 match_type = no_match;
1145
1146 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001147 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001148 if ((cmd_element = vector_slot (v, i)) != NULL)
1149 {
paul55468c82005-03-14 20:19:01 +00001150 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001151 vector_slot (v, i) = NULL;
1152 else
1153 {
hasso8c328f12004-10-05 21:01:23 +00001154 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001155 int matched = 0;
1156
1157 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001158
paul55468c82005-03-14 20:19:01 +00001159 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001160 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001161 {
1162 str = desc->cmd;
1163
1164 if (CMD_VARARG (str))
1165 {
1166 if (match_type < vararg_match)
1167 match_type = vararg_match;
1168 matched++;
1169 }
1170 else if (CMD_RANGE (str))
1171 {
1172 if (cmd_range_match (str, command))
1173 {
1174 if (match_type < range_match)
1175 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001176
paul909a2152005-03-14 17:41:45 +00001177 matched++;
1178 }
1179 }
paul22e0a9e2003-07-11 17:55:46 +00001180#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001181 else if (CMD_IPV6 (str))
1182 {
1183 if (cmd_ipv6_match (command))
1184 {
1185 if (match_type < ipv6_match)
1186 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001187
paul909a2152005-03-14 17:41:45 +00001188 matched++;
1189 }
1190 }
1191 else if (CMD_IPV6_PREFIX (str))
1192 {
1193 if (cmd_ipv6_prefix_match (command))
1194 {
1195 if (match_type < ipv6_prefix_match)
1196 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001197
paul909a2152005-03-14 17:41:45 +00001198 matched++;
1199 }
1200 }
1201#endif /* HAVE_IPV6 */
1202 else if (CMD_IPV4 (str))
1203 {
1204 if (cmd_ipv4_match (command))
1205 {
1206 if (match_type < ipv4_match)
1207 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001208
paul909a2152005-03-14 17:41:45 +00001209 matched++;
1210 }
1211 }
1212 else if (CMD_IPV4_PREFIX (str))
1213 {
1214 if (cmd_ipv4_prefix_match (command))
1215 {
1216 if (match_type < ipv4_prefix_match)
1217 match_type = ipv4_prefix_match;
1218 matched++;
1219 }
1220 }
1221 else
1222 /* Check is this point's argument optional ? */
1223 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1224 {
1225 if (match_type < extend_match)
1226 match_type = extend_match;
1227 matched++;
1228 }
1229 else if (strncmp (command, str, strlen (command)) == 0)
1230 {
1231 if (strcmp (command, str) == 0)
1232 match_type = exact_match;
1233 else
1234 {
1235 if (match_type < partly_match)
1236 match_type = partly_match;
1237 }
1238 matched++;
1239 }
1240 }
1241 if (!matched)
paul718e3742002-12-13 20:15:29 +00001242 vector_slot (v, i) = NULL;
1243 }
1244 }
1245 return match_type;
1246}
1247
1248/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001249static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001250cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001251{
hasso8c328f12004-10-05 21:01:23 +00001252 unsigned int i;
1253 const char *str;
paul718e3742002-12-13 20:15:29 +00001254 struct cmd_element *cmd_element;
1255 enum match_type match_type;
1256 vector descvec;
1257 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001258
paul718e3742002-12-13 20:15:29 +00001259 match_type = no_match;
1260
1261 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001262 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001263 if ((cmd_element = vector_slot (v, i)) != NULL)
1264 {
1265 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001266 set NULL */
paul55468c82005-03-14 20:19:01 +00001267 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001268 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001269 else
paul718e3742002-12-13 20:15:29 +00001270 {
hasso8c328f12004-10-05 21:01:23 +00001271 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001272 int matched = 0;
1273
1274 descvec = vector_slot (cmd_element->strvec, index);
1275
paul55468c82005-03-14 20:19:01 +00001276 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001277 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001278 {
1279 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001280
paul909a2152005-03-14 17:41:45 +00001281 if (CMD_VARARG (str))
1282 {
1283 if (match_type < vararg_match)
1284 match_type = vararg_match;
1285 matched++;
1286 }
1287 else if (CMD_RANGE (str))
1288 {
1289 if (cmd_range_match (str, command))
1290 {
1291 if (match_type < range_match)
1292 match_type = range_match;
1293 matched++;
1294 }
1295 }
paul22e0a9e2003-07-11 17:55:46 +00001296#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001297 else if (CMD_IPV6 (str))
1298 {
1299 if (cmd_ipv6_match (command) == exact_match)
1300 {
1301 if (match_type < ipv6_match)
1302 match_type = ipv6_match;
1303 matched++;
1304 }
1305 }
1306 else if (CMD_IPV6_PREFIX (str))
1307 {
1308 if (cmd_ipv6_prefix_match (command) == exact_match)
1309 {
1310 if (match_type < ipv6_prefix_match)
1311 match_type = ipv6_prefix_match;
1312 matched++;
1313 }
1314 }
paul22e0a9e2003-07-11 17:55:46 +00001315#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001316 else if (CMD_IPV4 (str))
1317 {
1318 if (cmd_ipv4_match (command) == exact_match)
1319 {
1320 if (match_type < ipv4_match)
1321 match_type = ipv4_match;
1322 matched++;
1323 }
1324 }
1325 else if (CMD_IPV4_PREFIX (str))
1326 {
1327 if (cmd_ipv4_prefix_match (command) == exact_match)
1328 {
1329 if (match_type < ipv4_prefix_match)
1330 match_type = ipv4_prefix_match;
1331 matched++;
1332 }
1333 }
1334 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1335 {
1336 if (match_type < extend_match)
1337 match_type = extend_match;
1338 matched++;
1339 }
1340 else
1341 {
1342 if (strcmp (command, str) == 0)
1343 {
1344 match_type = exact_match;
1345 matched++;
1346 }
1347 }
1348 }
1349 if (!matched)
paul718e3742002-12-13 20:15:29 +00001350 vector_slot (v, i) = NULL;
1351 }
1352 }
1353 return match_type;
1354}
1355
1356/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001357static int
paul718e3742002-12-13 20:15:29 +00001358is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1359{
hasso8c328f12004-10-05 21:01:23 +00001360 unsigned int i;
1361 unsigned int j;
1362 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001363 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001364 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001365 vector descvec;
1366 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001367
paul55468c82005-03-14 20:19:01 +00001368 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001369 if ((cmd_element = vector_slot (v, i)) != NULL)
1370 {
1371 int match = 0;
1372
1373 descvec = vector_slot (cmd_element->strvec, index);
1374
paul55468c82005-03-14 20:19:01 +00001375 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001376 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001377 {
1378 enum match_type ret;
1379
1380 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001381
paul909a2152005-03-14 17:41:45 +00001382 switch (type)
1383 {
1384 case exact_match:
1385 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1386 && strcmp (command, str) == 0)
1387 match++;
1388 break;
1389 case partly_match:
1390 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1391 && strncmp (command, str, strlen (command)) == 0)
1392 {
1393 if (matched && strcmp (matched, str) != 0)
1394 return 1; /* There is ambiguous match. */
1395 else
1396 matched = str;
1397 match++;
1398 }
1399 break;
1400 case range_match:
1401 if (cmd_range_match (str, command))
1402 {
1403 if (matched && strcmp (matched, str) != 0)
1404 return 1;
1405 else
1406 matched = str;
1407 match++;
1408 }
1409 break;
1410#ifdef HAVE_IPV6
1411 case ipv6_match:
1412 if (CMD_IPV6 (str))
1413 match++;
1414 break;
1415 case ipv6_prefix_match:
1416 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1417 {
1418 if (ret == partly_match)
1419 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001420
paul909a2152005-03-14 17:41:45 +00001421 match++;
1422 }
1423 break;
1424#endif /* HAVE_IPV6 */
1425 case ipv4_match:
1426 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001427 match++;
paul909a2152005-03-14 17:41:45 +00001428 break;
1429 case ipv4_prefix_match:
1430 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1431 {
1432 if (ret == partly_match)
1433 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001434
paul909a2152005-03-14 17:41:45 +00001435 match++;
1436 }
1437 break;
1438 case extend_match:
1439 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001440 match++;
paul909a2152005-03-14 17:41:45 +00001441 break;
1442 case no_match:
1443 default:
1444 break;
1445 }
1446 }
1447 if (!match)
paul718e3742002-12-13 20:15:29 +00001448 vector_slot (v, i) = NULL;
1449 }
1450 return 0;
1451}
1452
1453/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001454static const char *
hasso8c328f12004-10-05 21:01:23 +00001455cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001456{
1457 /* Skip variable arguments. */
1458 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1459 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1460 return NULL;
1461
1462 /* In case of 'command \t', given src is NULL string. */
1463 if (src == NULL)
1464 return dst;
1465
1466 /* Matched with input string. */
1467 if (strncmp (src, dst, strlen (src)) == 0)
1468 return dst;
1469
1470 return NULL;
1471}
1472
1473/* If src matches dst return dst string, otherwise return NULL */
1474/* This version will return the dst string always if it is
1475 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001476static const char *
hasso8c328f12004-10-05 21:01:23 +00001477cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001478{
1479 if (CMD_VARARG (dst))
1480 return dst;
1481
1482 if (CMD_RANGE (dst))
1483 {
1484 if (cmd_range_match (dst, src))
1485 return dst;
1486 else
1487 return NULL;
1488 }
1489
paul22e0a9e2003-07-11 17:55:46 +00001490#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001491 if (CMD_IPV6 (dst))
1492 {
1493 if (cmd_ipv6_match (src))
1494 return dst;
1495 else
1496 return NULL;
1497 }
1498
1499 if (CMD_IPV6_PREFIX (dst))
1500 {
1501 if (cmd_ipv6_prefix_match (src))
1502 return dst;
1503 else
1504 return NULL;
1505 }
paul22e0a9e2003-07-11 17:55:46 +00001506#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001507
1508 if (CMD_IPV4 (dst))
1509 {
1510 if (cmd_ipv4_match (src))
1511 return dst;
1512 else
1513 return NULL;
1514 }
1515
1516 if (CMD_IPV4_PREFIX (dst))
1517 {
1518 if (cmd_ipv4_prefix_match (src))
1519 return dst;
1520 else
1521 return NULL;
1522 }
1523
1524 /* Optional or variable commands always match on '?' */
1525 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1526 return dst;
1527
1528 /* In case of 'command \t', given src is NULL string. */
1529 if (src == NULL)
1530 return dst;
1531
1532 if (strncmp (src, dst, strlen (src)) == 0)
1533 return dst;
1534 else
1535 return NULL;
1536}
1537
1538/* Check same string element existence. If it isn't there return
1539 1. */
ajs274a4a42004-12-07 15:39:31 +00001540static int
hasso8c328f12004-10-05 21:01:23 +00001541cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001542{
hasso8c328f12004-10-05 21:01:23 +00001543 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001544 char *match;
1545
paul55468c82005-03-14 20:19:01 +00001546 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001547 if ((match = vector_slot (v, i)) != NULL)
1548 if (strcmp (match, str) == 0)
1549 return 0;
1550 return 1;
1551}
1552
1553/* Compare string to description vector. If there is same string
1554 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001555static int
hasso8c328f12004-10-05 21:01:23 +00001556desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001557{
hasso8c328f12004-10-05 21:01:23 +00001558 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001559 struct desc *desc;
1560
paul55468c82005-03-14 20:19:01 +00001561 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001562 if ((desc = vector_slot (v, i)) != NULL)
1563 if (strcmp (desc->cmd, str) == 0)
1564 return 1;
1565 return 0;
1566}
1567
ajs274a4a42004-12-07 15:39:31 +00001568static int
paulb92938a2002-12-13 21:20:42 +00001569cmd_try_do_shortcut (enum node_type node, char* first_word) {
1570 if ( first_word != NULL &&
1571 node != AUTH_NODE &&
1572 node != VIEW_NODE &&
1573 node != AUTH_ENABLE_NODE &&
1574 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01001575 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00001576 0 == strcmp( "do", first_word ) )
1577 return 1;
1578 return 0;
1579}
1580
paul718e3742002-12-13 20:15:29 +00001581/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001582static vector
paulb92938a2002-12-13 21:20:42 +00001583cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001584{
paulb8961472005-03-14 17:35:52 +00001585 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001586 vector cmd_vector;
1587#define INIT_MATCHVEC_SIZE 10
1588 vector matchvec;
1589 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001590 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001591 int ret;
1592 enum match_type match;
1593 char *command;
paul718e3742002-12-13 20:15:29 +00001594
1595 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001596 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001597 {
1598 *status = CMD_ERR_NO_MATCH;
1599 return NULL;
1600 }
1601 else
paul55468c82005-03-14 20:19:01 +00001602 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001603
paul718e3742002-12-13 20:15:29 +00001604 /* Make copy vector of current node's command vector. */
1605 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1606
1607 /* Prepare match vector */
1608 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1609
1610 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001611 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001612 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001613 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001614 {
1615 match = cmd_filter_by_completion (command, cmd_vector, i);
1616
1617 if (match == vararg_match)
1618 {
1619 struct cmd_element *cmd_element;
1620 vector descvec;
1621 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001622
paul55468c82005-03-14 20:19:01 +00001623 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001624 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001625 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001626 {
1627 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001628 vector_active (cmd_element->strvec) - 1);
1629 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001630 {
1631 struct desc *desc = vector_slot (descvec, k);
1632 vector_set (matchvec, desc);
1633 }
1634 }
1635
1636 vector_set (matchvec, &desc_cr);
1637 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001638
paul909a2152005-03-14 17:41:45 +00001639 return matchvec;
1640 }
paul718e3742002-12-13 20:15:29 +00001641
paul909a2152005-03-14 17:41:45 +00001642 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1643 {
1644 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001645 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001646 *status = CMD_ERR_AMBIGUOUS;
1647 return NULL;
1648 }
1649 else if (ret == 2)
1650 {
1651 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001652 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001653 *status = CMD_ERR_NO_MATCH;
1654 return NULL;
1655 }
1656 }
paul718e3742002-12-13 20:15:29 +00001657
1658 /* Prepare match vector */
1659 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1660
paul54aba542003-08-21 20:28:24 +00001661 /* Make sure that cmd_vector is filtered based on current word */
1662 command = vector_slot (vline, index);
1663 if (command)
1664 match = cmd_filter_by_completion (command, cmd_vector, index);
1665
paul718e3742002-12-13 20:15:29 +00001666 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001667 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001668 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1669 {
paul718e3742002-12-13 20:15:29 +00001670 vector strvec = cmd_element->strvec;
1671
paul55468c82005-03-14 20:19:01 +00001672 /* if command is NULL, index may be equal to vector_active */
1673 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001674 vector_slot (cmd_vector, i) = NULL;
1675 else
1676 {
paul54aba542003-08-21 20:28:24 +00001677 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001678 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001679 {
Chris Caputo228da422009-07-18 05:44:03 +00001680 if (!desc_unique_string (matchvec, command_cr))
paul718e3742002-12-13 20:15:29 +00001681 vector_set (matchvec, &desc_cr);
1682 }
1683 else
1684 {
hasso8c328f12004-10-05 21:01:23 +00001685 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001686 vector descvec = vector_slot (strvec, index);
1687 struct desc *desc;
1688
paul55468c82005-03-14 20:19:01 +00001689 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001690 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001691 {
Chris Caputo228da422009-07-18 05:44:03 +00001692 const char *string;
1693
paul909a2152005-03-14 17:41:45 +00001694 string = cmd_entry_function_desc (command, desc->cmd);
1695 if (string)
1696 {
1697 /* Uniqueness check */
1698 if (!desc_unique_string (matchvec, string))
1699 vector_set (matchvec, desc);
1700 }
1701 }
paul718e3742002-12-13 20:15:29 +00001702 }
1703 }
1704 }
1705 vector_free (cmd_vector);
1706
1707 if (vector_slot (matchvec, 0) == NULL)
1708 {
1709 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001710 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001711 return NULL;
paul718e3742002-12-13 20:15:29 +00001712 }
paul718e3742002-12-13 20:15:29 +00001713
Paul Jakma5fc60512006-05-12 23:24:09 +00001714 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001715 return matchvec;
1716}
1717
paulb92938a2002-12-13 21:20:42 +00001718vector
1719cmd_describe_command (vector vline, struct vty *vty, int *status)
1720{
1721 vector ret;
1722
1723 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1724 {
1725 enum node_type onode;
1726 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001727 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001728
1729 onode = vty->node;
1730 vty->node = ENABLE_NODE;
1731 /* We can try it on enable node, cos' the vty is authenticated */
1732
1733 shifted_vline = vector_init (vector_count(vline));
1734 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001735 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001736 {
1737 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1738 }
1739
1740 ret = cmd_describe_command_real (shifted_vline, vty, status);
1741
1742 vector_free(shifted_vline);
1743 vty->node = onode;
1744 return ret;
1745 }
1746
1747
1748 return cmd_describe_command_real (vline, vty, status);
1749}
1750
1751
paul718e3742002-12-13 20:15:29 +00001752/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001753static int
paul718e3742002-12-13 20:15:29 +00001754cmd_lcd (char **matched)
1755{
1756 int i;
1757 int j;
1758 int lcd = -1;
1759 char *s1, *s2;
1760 char c1, c2;
1761
1762 if (matched[0] == NULL || matched[1] == NULL)
1763 return 0;
1764
1765 for (i = 1; matched[i] != NULL; i++)
1766 {
1767 s1 = matched[i - 1];
1768 s2 = matched[i];
1769
1770 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1771 if (c1 != c2)
1772 break;
1773
1774 if (lcd < 0)
1775 lcd = j;
1776 else
1777 {
1778 if (lcd > j)
1779 lcd = j;
1780 }
1781 }
1782 return lcd;
1783}
1784
1785/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001786static char **
paulb92938a2002-12-13 21:20:42 +00001787cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001788{
paulb8961472005-03-14 17:35:52 +00001789 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001790 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1791#define INIT_MATCHVEC_SIZE 10
1792 vector matchvec;
1793 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001794 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001795 char **match_str;
1796 struct desc *desc;
1797 vector descvec;
1798 char *command;
1799 int lcd;
1800
paul55468c82005-03-14 20:19:01 +00001801 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001802 {
Paul Jakmad2519962006-05-12 23:19:37 +00001803 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001804 *status = CMD_ERR_NO_MATCH;
1805 return NULL;
1806 }
1807 else
paul55468c82005-03-14 20:19:01 +00001808 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001809
paul718e3742002-12-13 20:15:29 +00001810 /* First, filter by preceeding command string */
1811 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001812 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001813 {
1814 enum match_type match;
1815 int ret;
paul718e3742002-12-13 20:15:29 +00001816
paul909a2152005-03-14 17:41:45 +00001817 /* First try completion match, if there is exactly match return 1 */
1818 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001819
paul909a2152005-03-14 17:41:45 +00001820 /* If there is exact match then filter ambiguous match else check
1821 ambiguousness. */
1822 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1823 {
1824 vector_free (cmd_vector);
1825 *status = CMD_ERR_AMBIGUOUS;
1826 return NULL;
1827 }
1828 /*
1829 else if (ret == 2)
1830 {
1831 vector_free (cmd_vector);
1832 *status = CMD_ERR_NO_MATCH;
1833 return NULL;
1834 }
1835 */
1836 }
1837
paul718e3742002-12-13 20:15:29 +00001838 /* Prepare match vector. */
1839 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1840
1841 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001842 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001843 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001844 {
hasso8c328f12004-10-05 21:01:23 +00001845 const char *string;
paul718e3742002-12-13 20:15:29 +00001846 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001847
paul718e3742002-12-13 20:15:29 +00001848 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001849 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001850 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001851 else
paul718e3742002-12-13 20:15:29 +00001852 {
hasso8c328f12004-10-05 21:01:23 +00001853 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001854
1855 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001856 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001857 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001858 {
paulb8961472005-03-14 17:35:52 +00001859 if ((string =
1860 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001861 desc->cmd)))
1862 if (cmd_unique_string (matchvec, string))
1863 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1864 }
paul718e3742002-12-13 20:15:29 +00001865 }
1866 }
1867
1868 /* We don't need cmd_vector any more. */
1869 vector_free (cmd_vector);
1870
1871 /* No matched command */
1872 if (vector_slot (matchvec, 0) == NULL)
1873 {
1874 vector_free (matchvec);
1875
1876 /* In case of 'command \t' pattern. Do you need '?' command at
1877 the end of the line. */
1878 if (vector_slot (vline, index) == '\0')
1879 *status = CMD_ERR_NOTHING_TODO;
1880 else
1881 *status = CMD_ERR_NO_MATCH;
1882 return NULL;
1883 }
1884
1885 /* Only one matched */
1886 if (vector_slot (matchvec, 1) == NULL)
1887 {
1888 match_str = (char **) matchvec->index;
1889 vector_only_wrapper_free (matchvec);
1890 *status = CMD_COMPLETE_FULL_MATCH;
1891 return match_str;
1892 }
1893 /* Make it sure last element is NULL. */
1894 vector_set (matchvec, NULL);
1895
1896 /* Check LCD of matched strings. */
1897 if (vector_slot (vline, index) != NULL)
1898 {
1899 lcd = cmd_lcd ((char **) matchvec->index);
1900
1901 if (lcd)
1902 {
1903 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001904
paul718e3742002-12-13 20:15:29 +00001905 if (len < lcd)
1906 {
1907 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001908
paul05865c92005-10-26 05:49:54 +00001909 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001910 memcpy (lcdstr, matchvec->index[0], lcd);
1911 lcdstr[lcd] = '\0';
1912
1913 /* match_str = (char **) &lcdstr; */
1914
1915 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001916 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001917 {
1918 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001919 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001920 }
1921 vector_free (matchvec);
1922
paul909a2152005-03-14 17:41:45 +00001923 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001924 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1925 vector_set (matchvec, lcdstr);
1926 match_str = (char **) matchvec->index;
1927 vector_only_wrapper_free (matchvec);
1928
1929 *status = CMD_COMPLETE_MATCH;
1930 return match_str;
1931 }
1932 }
1933 }
1934
1935 match_str = (char **) matchvec->index;
1936 vector_only_wrapper_free (matchvec);
1937 *status = CMD_COMPLETE_LIST_MATCH;
1938 return match_str;
1939}
1940
paulb92938a2002-12-13 21:20:42 +00001941char **
paul9ab68122003-01-18 01:16:20 +00001942cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001943{
1944 char **ret;
1945
1946 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1947 {
1948 enum node_type onode;
1949 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001950 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001951
1952 onode = vty->node;
1953 vty->node = ENABLE_NODE;
1954 /* We can try it on enable node, cos' the vty is authenticated */
1955
1956 shifted_vline = vector_init (vector_count(vline));
1957 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001958 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001959 {
1960 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1961 }
1962
1963 ret = cmd_complete_command_real (shifted_vline, vty, status);
1964
1965 vector_free(shifted_vline);
1966 vty->node = onode;
1967 return ret;
1968 }
1969
1970
1971 return cmd_complete_command_real (vline, vty, status);
1972}
1973
1974/* return parent node */
1975/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001976enum node_type
ajs274a4a42004-12-07 15:39:31 +00001977node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001978{
1979 enum node_type ret;
1980
paul9ab68122003-01-18 01:16:20 +00001981 assert (node > CONFIG_NODE);
1982
1983 switch (node)
1984 {
1985 case BGP_VPNV4_NODE:
1986 case BGP_IPV4_NODE:
1987 case BGP_IPV4M_NODE:
1988 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001989 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001990 ret = BGP_NODE;
1991 break;
1992 case KEYCHAIN_KEY_NODE:
1993 ret = KEYCHAIN_NODE;
1994 break;
1995 default:
1996 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001997 }
1998
1999 return ret;
2000}
2001
paul718e3742002-12-13 20:15:29 +00002002/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00002003static int
paulb8961472005-03-14 17:35:52 +00002004cmd_execute_command_real (vector vline, struct vty *vty,
2005 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00002006{
hasso8c328f12004-10-05 21:01:23 +00002007 unsigned int i;
2008 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002009 vector cmd_vector;
2010 struct cmd_element *cmd_element;
2011 struct cmd_element *matched_element;
2012 unsigned int matched_count, incomplete_count;
2013 int argc;
paul9035efa2004-10-10 11:56:56 +00002014 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002015 enum match_type match = 0;
2016 int varflag;
2017 char *command;
2018
2019 /* Make copy of command elements. */
2020 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2021
paul55468c82005-03-14 20:19:01 +00002022 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002023 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002024 {
2025 int ret;
paul718e3742002-12-13 20:15:29 +00002026
paul909a2152005-03-14 17:41:45 +00002027 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002028
paul909a2152005-03-14 17:41:45 +00002029 if (match == vararg_match)
2030 break;
2031
2032 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00002033
paul909a2152005-03-14 17:41:45 +00002034 if (ret == 1)
2035 {
2036 vector_free (cmd_vector);
2037 return CMD_ERR_AMBIGUOUS;
2038 }
2039 else if (ret == 2)
2040 {
2041 vector_free (cmd_vector);
2042 return CMD_ERR_NO_MATCH;
2043 }
2044 }
paul718e3742002-12-13 20:15:29 +00002045
2046 /* Check matched count. */
2047 matched_element = NULL;
2048 matched_count = 0;
2049 incomplete_count = 0;
2050
paul55468c82005-03-14 20:19:01 +00002051 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00002052 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00002053 {
paul718e3742002-12-13 20:15:29 +00002054 if (match == vararg_match || index >= cmd_element->cmdsize)
2055 {
2056 matched_element = cmd_element;
2057#if 0
2058 printf ("DEBUG: %s\n", cmd_element->string);
2059#endif
2060 matched_count++;
2061 }
2062 else
2063 {
2064 incomplete_count++;
2065 }
2066 }
paul909a2152005-03-14 17:41:45 +00002067
paul718e3742002-12-13 20:15:29 +00002068 /* Finish of using cmd_vector. */
2069 vector_free (cmd_vector);
2070
paul909a2152005-03-14 17:41:45 +00002071 /* To execute command, matched_count must be 1. */
2072 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002073 {
2074 if (incomplete_count)
2075 return CMD_ERR_INCOMPLETE;
2076 else
2077 return CMD_ERR_NO_MATCH;
2078 }
2079
paul909a2152005-03-14 17:41:45 +00002080 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002081 return CMD_ERR_AMBIGUOUS;
2082
2083 /* Argument treatment */
2084 varflag = 0;
2085 argc = 0;
2086
paul55468c82005-03-14 20:19:01 +00002087 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002088 {
2089 if (varflag)
2090 argv[argc++] = vector_slot (vline, i);
2091 else
paul909a2152005-03-14 17:41:45 +00002092 {
paul718e3742002-12-13 20:15:29 +00002093 vector descvec = vector_slot (matched_element->strvec, i);
2094
paul55468c82005-03-14 20:19:01 +00002095 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002096 {
2097 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002098
hasso8c328f12004-10-05 21:01:23 +00002099 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002100 varflag = 1;
2101
hasso8c328f12004-10-05 21:01:23 +00002102 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002103 argv[argc++] = vector_slot (vline, i);
2104 }
2105 else
2106 argv[argc++] = vector_slot (vline, i);
2107 }
2108
2109 if (argc >= CMD_ARGC_MAX)
2110 return CMD_ERR_EXEED_ARGC_MAX;
2111 }
2112
2113 /* For vtysh execution. */
2114 if (cmd)
2115 *cmd = matched_element;
2116
2117 if (matched_element->daemon)
2118 return CMD_SUCCESS_DAEMON;
2119
2120 /* Execute matched command. */
2121 return (*matched_element->func) (matched_element, vty, argc, argv);
2122}
2123
paulb92938a2002-12-13 21:20:42 +00002124int
hasso87d683b2005-01-16 23:31:54 +00002125cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2126 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002127 int ret, saved_ret, tried = 0;
2128 enum node_type onode, try_node;
2129
2130 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002131
2132 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2133 {
2134 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002135 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002136
2137 vty->node = ENABLE_NODE;
2138 /* We can try it on enable node, cos' the vty is authenticated */
2139
2140 shifted_vline = vector_init (vector_count(vline));
2141 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002142 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002143 {
2144 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2145 }
2146
2147 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2148
2149 vector_free(shifted_vline);
2150 vty->node = onode;
2151 return ret;
2152 }
2153
2154
paul9ab68122003-01-18 01:16:20 +00002155 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002156
hasso87d683b2005-01-16 23:31:54 +00002157 if (vtysh)
2158 return saved_ret;
2159
paulb92938a2002-12-13 21:20:42 +00002160 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002161 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002162 && vty->node > CONFIG_NODE )
2163 {
paul9ab68122003-01-18 01:16:20 +00002164 try_node = node_parent(try_node);
2165 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002166 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002167 tried = 1;
2168 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002169 {
paul9ab68122003-01-18 01:16:20 +00002170 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002171 return ret;
2172 }
paulb92938a2002-12-13 21:20:42 +00002173 }
paul9ab68122003-01-18 01:16:20 +00002174 /* no command succeeded, reset the vty to the original node and
2175 return the error for this node */
2176 if ( tried )
2177 vty->node = onode;
2178 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002179}
2180
paul718e3742002-12-13 20:15:29 +00002181/* Execute command by argument readline. */
2182int
paul909a2152005-03-14 17:41:45 +00002183cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002184 struct cmd_element **cmd)
2185{
hasso8c328f12004-10-05 21:01:23 +00002186 unsigned int i;
2187 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002188 vector cmd_vector;
2189 struct cmd_element *cmd_element;
2190 struct cmd_element *matched_element;
2191 unsigned int matched_count, incomplete_count;
2192 int argc;
paul9035efa2004-10-10 11:56:56 +00002193 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002194 int varflag;
2195 enum match_type match = 0;
2196 char *command;
2197
2198 /* Make copy of command element */
2199 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2200
paul55468c82005-03-14 20:19:01 +00002201 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002202 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002203 {
2204 int ret;
2205
2206 match = cmd_filter_by_string (vector_slot (vline, index),
2207 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002208
paul909a2152005-03-14 17:41:45 +00002209 /* If command meets '.VARARG' then finish matching. */
2210 if (match == vararg_match)
2211 break;
2212
2213 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2214 if (ret == 1)
2215 {
2216 vector_free (cmd_vector);
2217 return CMD_ERR_AMBIGUOUS;
2218 }
2219 if (ret == 2)
2220 {
2221 vector_free (cmd_vector);
2222 return CMD_ERR_NO_MATCH;
2223 }
2224 }
paul718e3742002-12-13 20:15:29 +00002225
2226 /* Check matched count. */
2227 matched_element = NULL;
2228 matched_count = 0;
2229 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002230 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002231 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002232 {
paul909a2152005-03-14 17:41:45 +00002233 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002234
2235 if (match == vararg_match || index >= cmd_element->cmdsize)
2236 {
2237 matched_element = cmd_element;
2238 matched_count++;
2239 }
2240 else
2241 incomplete_count++;
2242 }
paul909a2152005-03-14 17:41:45 +00002243
paul718e3742002-12-13 20:15:29 +00002244 /* Finish of using cmd_vector. */
2245 vector_free (cmd_vector);
2246
paul909a2152005-03-14 17:41:45 +00002247 /* To execute command, matched_count must be 1. */
2248 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002249 {
2250 if (incomplete_count)
2251 return CMD_ERR_INCOMPLETE;
2252 else
2253 return CMD_ERR_NO_MATCH;
2254 }
2255
paul909a2152005-03-14 17:41:45 +00002256 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002257 return CMD_ERR_AMBIGUOUS;
2258
2259 /* Argument treatment */
2260 varflag = 0;
2261 argc = 0;
2262
paul55468c82005-03-14 20:19:01 +00002263 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002264 {
2265 if (varflag)
2266 argv[argc++] = vector_slot (vline, i);
2267 else
paul909a2152005-03-14 17:41:45 +00002268 {
paul718e3742002-12-13 20:15:29 +00002269 vector descvec = vector_slot (matched_element->strvec, i);
2270
paul55468c82005-03-14 20:19:01 +00002271 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002272 {
2273 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002274
hasso8c328f12004-10-05 21:01:23 +00002275 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002276 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002277
hasso8c328f12004-10-05 21:01:23 +00002278 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002279 argv[argc++] = vector_slot (vline, i);
2280 }
2281 else
2282 argv[argc++] = vector_slot (vline, i);
2283 }
2284
2285 if (argc >= CMD_ARGC_MAX)
2286 return CMD_ERR_EXEED_ARGC_MAX;
2287 }
2288
2289 /* For vtysh execution. */
2290 if (cmd)
2291 *cmd = matched_element;
2292
2293 if (matched_element->daemon)
2294 return CMD_SUCCESS_DAEMON;
2295
2296 /* Now execute matched command */
2297 return (*matched_element->func) (matched_element, vty, argc, argv);
2298}
2299
2300/* Configration make from file. */
2301int
2302config_from_file (struct vty *vty, FILE *fp)
2303{
2304 int ret;
2305 vector vline;
2306
2307 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2308 {
2309 vline = cmd_make_strvec (vty->buf);
2310
2311 /* In case of comment line */
2312 if (vline == NULL)
2313 continue;
2314 /* Execute configuration command : this is strict match */
2315 ret = cmd_execute_command_strict (vline, vty, NULL);
2316
2317 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002318 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002319 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2320 {
paulb92938a2002-12-13 21:20:42 +00002321 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002322 ret = cmd_execute_command_strict (vline, vty, NULL);
2323 }
paul9ab68122003-01-18 01:16:20 +00002324
paul718e3742002-12-13 20:15:29 +00002325 cmd_free_strvec (vline);
2326
hassoddd85ed2004-10-13 08:18:07 +00002327 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2328 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002329 return ret;
2330 }
2331 return CMD_SUCCESS;
2332}
2333
2334/* Configration from terminal */
2335DEFUN (config_terminal,
2336 config_terminal_cmd,
2337 "configure terminal",
2338 "Configuration from vty interface\n"
2339 "Configuration terminal\n")
2340{
2341 if (vty_config_lock (vty))
2342 vty->node = CONFIG_NODE;
2343 else
2344 {
2345 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2346 return CMD_WARNING;
2347 }
2348 return CMD_SUCCESS;
2349}
2350
2351/* Enable command */
2352DEFUN (enable,
2353 config_enable_cmd,
2354 "enable",
2355 "Turn on privileged mode command\n")
2356{
2357 /* If enable password is NULL, change to ENABLE_NODE */
2358 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2359 vty->type == VTY_SHELL_SERV)
2360 vty->node = ENABLE_NODE;
2361 else
2362 vty->node = AUTH_ENABLE_NODE;
2363
2364 return CMD_SUCCESS;
2365}
2366
2367/* Disable command */
2368DEFUN (disable,
2369 config_disable_cmd,
2370 "disable",
2371 "Turn off privileged mode command\n")
2372{
2373 if (vty->node == ENABLE_NODE)
2374 vty->node = VIEW_NODE;
2375 return CMD_SUCCESS;
2376}
2377
2378/* Down vty node level. */
2379DEFUN (config_exit,
2380 config_exit_cmd,
2381 "exit",
2382 "Exit current mode and down to previous mode\n")
2383{
2384 switch (vty->node)
2385 {
2386 case VIEW_NODE:
2387 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002388 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002389 if (vty_shell (vty))
2390 exit (0);
2391 else
2392 vty->status = VTY_CLOSE;
2393 break;
2394 case CONFIG_NODE:
2395 vty->node = ENABLE_NODE;
2396 vty_config_unlock (vty);
2397 break;
2398 case INTERFACE_NODE:
2399 case ZEBRA_NODE:
2400 case BGP_NODE:
2401 case RIP_NODE:
2402 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002403 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002404 case OSPF_NODE:
2405 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002406 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002407 case KEYCHAIN_NODE:
2408 case MASC_NODE:
2409 case RMAP_NODE:
2410 case VTY_NODE:
2411 vty->node = CONFIG_NODE;
2412 break;
2413 case BGP_VPNV4_NODE:
2414 case BGP_IPV4_NODE:
2415 case BGP_IPV4M_NODE:
2416 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002417 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002418 vty->node = BGP_NODE;
2419 break;
2420 case KEYCHAIN_KEY_NODE:
2421 vty->node = KEYCHAIN_NODE;
2422 break;
2423 default:
2424 break;
2425 }
2426 return CMD_SUCCESS;
2427}
2428
2429/* quit is alias of exit. */
2430ALIAS (config_exit,
2431 config_quit_cmd,
2432 "quit",
2433 "Exit current mode and down to previous mode\n")
2434
2435/* End of configuration. */
2436DEFUN (config_end,
2437 config_end_cmd,
2438 "end",
2439 "End current mode and change to enable mode.")
2440{
2441 switch (vty->node)
2442 {
2443 case VIEW_NODE:
2444 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002445 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002446 /* Nothing to do. */
2447 break;
2448 case CONFIG_NODE:
2449 case INTERFACE_NODE:
2450 case ZEBRA_NODE:
2451 case RIP_NODE:
2452 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002453 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002454 case BGP_NODE:
2455 case BGP_VPNV4_NODE:
2456 case BGP_IPV4_NODE:
2457 case BGP_IPV4M_NODE:
2458 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002459 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002460 case RMAP_NODE:
2461 case OSPF_NODE:
2462 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002463 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002464 case KEYCHAIN_NODE:
2465 case KEYCHAIN_KEY_NODE:
2466 case MASC_NODE:
2467 case VTY_NODE:
2468 vty_config_unlock (vty);
2469 vty->node = ENABLE_NODE;
2470 break;
2471 default:
2472 break;
2473 }
2474 return CMD_SUCCESS;
2475}
2476
2477/* Show version. */
2478DEFUN (show_version,
2479 show_version_cmd,
2480 "show version",
2481 SHOW_STR
2482 "Displays zebra version\n")
2483{
hasso12f6ea22005-03-07 08:35:39 +00002484 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2485 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002486 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002487
2488 return CMD_SUCCESS;
2489}
2490
2491/* Help display function for all node. */
2492DEFUN (config_help,
2493 config_help_cmd,
2494 "help",
2495 "Description of the interactive help system\n")
2496{
2497 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002498 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002499anytime at the command line please press '?'.%s\
2500%s\
2501If nothing matches, the help list will be empty and you must backup%s\
2502 until entering a '?' shows the available options.%s\
2503Two styles of help are provided:%s\
25041. Full help is available when you are ready to enter a%s\
2505command argument (e.g. 'show ?') and describes each possible%s\
2506argument.%s\
25072. Partial help is provided when an abbreviated argument is entered%s\
2508 and you want to know what arguments match the input%s\
2509 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2510 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2511 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2512 return CMD_SUCCESS;
2513}
2514
2515/* Help display function for all node. */
2516DEFUN (config_list,
2517 config_list_cmd,
2518 "list",
2519 "Print command list\n")
2520{
hasso8c328f12004-10-05 21:01:23 +00002521 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002522 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2523 struct cmd_element *cmd;
2524
paul55468c82005-03-14 20:19:01 +00002525 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002526 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2527 && !(cmd->attr == CMD_ATTR_DEPRECATED
2528 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002529 vty_out (vty, " %s%s", cmd->string,
2530 VTY_NEWLINE);
2531 return CMD_SUCCESS;
2532}
2533
2534/* Write current configuration into file. */
2535DEFUN (config_write_file,
2536 config_write_file_cmd,
2537 "write file",
2538 "Write running configuration to memory, network, or terminal\n"
2539 "Write to configuration file\n")
2540{
hasso8c328f12004-10-05 21:01:23 +00002541 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002542 int fd;
2543 struct cmd_node *node;
2544 char *config_file;
2545 char *config_file_tmp = NULL;
2546 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002547 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002548 struct vty *file_vty;
2549
2550 /* Check and see if we are operating under vtysh configuration */
2551 if (host.config == NULL)
2552 {
2553 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2554 VTY_NEWLINE);
2555 return CMD_WARNING;
2556 }
2557
2558 /* Get filename. */
2559 config_file = host.config;
2560
paul05865c92005-10-26 05:49:54 +00002561 config_file_sav =
2562 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002563 strcpy (config_file_sav, config_file);
2564 strcat (config_file_sav, CONF_BACKUP_EXT);
2565
2566
paul05865c92005-10-26 05:49:54 +00002567 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002568 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2569
2570 /* Open file to configuration write. */
2571 fd = mkstemp (config_file_tmp);
2572 if (fd < 0)
2573 {
2574 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2575 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002576 goto finished;
paul718e3742002-12-13 20:15:29 +00002577 }
2578
2579 /* Make vty for configuration file. */
2580 file_vty = vty_new ();
2581 file_vty->fd = fd;
2582 file_vty->type = VTY_FILE;
2583
2584 /* Config file header print. */
2585 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2586 vty_time_print (file_vty, 1);
2587 vty_out (file_vty, "!\n");
2588
paul55468c82005-03-14 20:19:01 +00002589 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002590 if ((node = vector_slot (cmdvec, i)) && node->func)
2591 {
2592 if ((*node->func) (file_vty))
2593 vty_out (file_vty, "!\n");
2594 }
2595 vty_close (file_vty);
2596
2597 if (unlink (config_file_sav) != 0)
2598 if (errno != ENOENT)
2599 {
2600 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2601 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002602 goto finished;
paul718e3742002-12-13 20:15:29 +00002603 }
2604 if (link (config_file, config_file_sav) != 0)
2605 {
2606 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2607 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002608 goto finished;
paul718e3742002-12-13 20:15:29 +00002609 }
2610 sync ();
2611 if (unlink (config_file) != 0)
2612 {
2613 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2614 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002615 goto finished;
paul718e3742002-12-13 20:15:29 +00002616 }
2617 if (link (config_file_tmp, config_file) != 0)
2618 {
2619 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2620 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002621 goto finished;
paul718e3742002-12-13 20:15:29 +00002622 }
paul718e3742002-12-13 20:15:29 +00002623 sync ();
2624
gdtaa593d52003-12-22 20:15:53 +00002625 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2626 {
2627 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002628 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002629 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002630 }
2631
paul718e3742002-12-13 20:15:29 +00002632 vty_out (vty, "Configuration saved to %s%s", config_file,
2633 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002634 ret = CMD_SUCCESS;
2635
2636finished:
2637 unlink (config_file_tmp);
2638 XFREE (MTYPE_TMP, config_file_tmp);
2639 XFREE (MTYPE_TMP, config_file_sav);
2640 return ret;
paul718e3742002-12-13 20:15:29 +00002641}
2642
2643ALIAS (config_write_file,
2644 config_write_cmd,
2645 "write",
2646 "Write running configuration to memory, network, or terminal\n")
2647
2648ALIAS (config_write_file,
2649 config_write_memory_cmd,
2650 "write memory",
2651 "Write running configuration to memory, network, or terminal\n"
2652 "Write configuration to the file (same as write file)\n")
2653
2654ALIAS (config_write_file,
2655 copy_runningconfig_startupconfig_cmd,
2656 "copy running-config startup-config",
2657 "Copy configuration\n"
2658 "Copy running config to... \n"
2659 "Copy running config to startup config (same as write file)\n")
2660
2661/* Write current configuration into the terminal. */
2662DEFUN (config_write_terminal,
2663 config_write_terminal_cmd,
2664 "write terminal",
2665 "Write running configuration to memory, network, or terminal\n"
2666 "Write to terminal\n")
2667{
hasso8c328f12004-10-05 21:01:23 +00002668 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002669 struct cmd_node *node;
2670
2671 if (vty->type == VTY_SHELL_SERV)
2672 {
paul55468c82005-03-14 20:19:01 +00002673 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002674 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2675 {
2676 if ((*node->func) (vty))
2677 vty_out (vty, "!%s", VTY_NEWLINE);
2678 }
2679 }
2680 else
2681 {
2682 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2683 VTY_NEWLINE);
2684 vty_out (vty, "!%s", VTY_NEWLINE);
2685
paul55468c82005-03-14 20:19:01 +00002686 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002687 if ((node = vector_slot (cmdvec, i)) && node->func)
2688 {
2689 if ((*node->func) (vty))
2690 vty_out (vty, "!%s", VTY_NEWLINE);
2691 }
2692 vty_out (vty, "end%s",VTY_NEWLINE);
2693 }
2694 return CMD_SUCCESS;
2695}
2696
2697/* Write current configuration into the terminal. */
2698ALIAS (config_write_terminal,
2699 show_running_config_cmd,
2700 "show running-config",
2701 SHOW_STR
2702 "running configuration\n")
2703
2704/* Write startup configuration into the terminal. */
2705DEFUN (show_startup_config,
2706 show_startup_config_cmd,
2707 "show startup-config",
2708 SHOW_STR
2709 "Contentes of startup configuration\n")
2710{
2711 char buf[BUFSIZ];
2712 FILE *confp;
2713
2714 confp = fopen (host.config, "r");
2715 if (confp == NULL)
2716 {
2717 vty_out (vty, "Can't open configuration file [%s]%s",
2718 host.config, VTY_NEWLINE);
2719 return CMD_WARNING;
2720 }
2721
2722 while (fgets (buf, BUFSIZ, confp))
2723 {
2724 char *cp = buf;
2725
2726 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2727 cp++;
2728 *cp = '\0';
2729
2730 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2731 }
2732
2733 fclose (confp);
2734
2735 return CMD_SUCCESS;
2736}
2737
2738/* Hostname configuration */
2739DEFUN (config_hostname,
2740 hostname_cmd,
2741 "hostname WORD",
2742 "Set system's network name\n"
2743 "This system's network name\n")
2744{
2745 if (!isalpha((int) *argv[0]))
2746 {
2747 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2748 return CMD_WARNING;
2749 }
2750
2751 if (host.name)
paul05865c92005-10-26 05:49:54 +00002752 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002753
paul05865c92005-10-26 05:49:54 +00002754 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002755 return CMD_SUCCESS;
2756}
2757
2758DEFUN (config_no_hostname,
2759 no_hostname_cmd,
2760 "no hostname [HOSTNAME]",
2761 NO_STR
2762 "Reset system's network name\n"
2763 "Host name of this router\n")
2764{
2765 if (host.name)
paul05865c92005-10-26 05:49:54 +00002766 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002767 host.name = NULL;
2768 return CMD_SUCCESS;
2769}
2770
2771/* VTY interface password set. */
2772DEFUN (config_password, password_cmd,
2773 "password (8|) WORD",
2774 "Assign the terminal connection password\n"
2775 "Specifies a HIDDEN password will follow\n"
2776 "dummy string \n"
2777 "The HIDDEN line password string\n")
2778{
2779 /* Argument check. */
2780 if (argc == 0)
2781 {
2782 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2783 return CMD_WARNING;
2784 }
2785
2786 if (argc == 2)
2787 {
2788 if (*argv[0] == '8')
2789 {
2790 if (host.password)
paul05865c92005-10-26 05:49:54 +00002791 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002792 host.password = NULL;
2793 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002794 XFREE (MTYPE_HOST, host.password_encrypt);
2795 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002796 return CMD_SUCCESS;
2797 }
2798 else
2799 {
2800 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2801 return CMD_WARNING;
2802 }
2803 }
2804
2805 if (!isalnum ((int) *argv[0]))
2806 {
2807 vty_out (vty,
2808 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2809 return CMD_WARNING;
2810 }
2811
2812 if (host.password)
paul05865c92005-10-26 05:49:54 +00002813 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002814 host.password = NULL;
2815
2816 if (host.encrypt)
2817 {
2818 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002819 XFREE (MTYPE_HOST, host.password_encrypt);
2820 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002821 }
2822 else
paul05865c92005-10-26 05:49:54 +00002823 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002824
2825 return CMD_SUCCESS;
2826}
2827
2828ALIAS (config_password, password_text_cmd,
2829 "password LINE",
2830 "Assign the terminal connection password\n"
2831 "The UNENCRYPTED (cleartext) line password\n")
2832
2833/* VTY enable password set. */
2834DEFUN (config_enable_password, enable_password_cmd,
2835 "enable password (8|) WORD",
2836 "Modify enable password parameters\n"
2837 "Assign the privileged level password\n"
2838 "Specifies a HIDDEN password will follow\n"
2839 "dummy string \n"
2840 "The HIDDEN 'enable' password string\n")
2841{
2842 /* Argument check. */
2843 if (argc == 0)
2844 {
2845 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2846 return CMD_WARNING;
2847 }
2848
2849 /* Crypt type is specified. */
2850 if (argc == 2)
2851 {
2852 if (*argv[0] == '8')
2853 {
2854 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002855 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002856 host.enable = NULL;
2857
2858 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002859 XFREE (MTYPE_HOST, host.enable_encrypt);
2860 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002861
2862 return CMD_SUCCESS;
2863 }
2864 else
2865 {
2866 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2867 return CMD_WARNING;
2868 }
2869 }
2870
2871 if (!isalnum ((int) *argv[0]))
2872 {
2873 vty_out (vty,
2874 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2875 return CMD_WARNING;
2876 }
2877
2878 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002879 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002880 host.enable = NULL;
2881
2882 /* Plain password input. */
2883 if (host.encrypt)
2884 {
2885 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002886 XFREE (MTYPE_HOST, host.enable_encrypt);
2887 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002888 }
2889 else
paul05865c92005-10-26 05:49:54 +00002890 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002891
2892 return CMD_SUCCESS;
2893}
2894
2895ALIAS (config_enable_password,
2896 enable_password_text_cmd,
2897 "enable password LINE",
2898 "Modify enable password parameters\n"
2899 "Assign the privileged level password\n"
2900 "The UNENCRYPTED (cleartext) 'enable' password\n")
2901
2902/* VTY enable password delete. */
2903DEFUN (no_config_enable_password, no_enable_password_cmd,
2904 "no enable password",
2905 NO_STR
2906 "Modify enable password parameters\n"
2907 "Assign the privileged level password\n")
2908{
2909 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002910 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002911 host.enable = NULL;
2912
2913 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002914 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002915 host.enable_encrypt = NULL;
2916
2917 return CMD_SUCCESS;
2918}
2919
2920DEFUN (service_password_encrypt,
2921 service_password_encrypt_cmd,
2922 "service password-encryption",
2923 "Set up miscellaneous service\n"
2924 "Enable encrypted passwords\n")
2925{
2926 if (host.encrypt)
2927 return CMD_SUCCESS;
2928
2929 host.encrypt = 1;
2930
2931 if (host.password)
2932 {
2933 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002934 XFREE (MTYPE_HOST, host.password_encrypt);
2935 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002936 }
2937 if (host.enable)
2938 {
2939 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002940 XFREE (MTYPE_HOST, host.enable_encrypt);
2941 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002942 }
2943
2944 return CMD_SUCCESS;
2945}
2946
2947DEFUN (no_service_password_encrypt,
2948 no_service_password_encrypt_cmd,
2949 "no service password-encryption",
2950 NO_STR
2951 "Set up miscellaneous service\n"
2952 "Enable encrypted passwords\n")
2953{
2954 if (! host.encrypt)
2955 return CMD_SUCCESS;
2956
2957 host.encrypt = 0;
2958
2959 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002960 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002961 host.password_encrypt = NULL;
2962
2963 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002964 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002965 host.enable_encrypt = NULL;
2966
2967 return CMD_SUCCESS;
2968}
2969
2970DEFUN (config_terminal_length, config_terminal_length_cmd,
2971 "terminal length <0-512>",
2972 "Set terminal line parameters\n"
2973 "Set number of lines on a screen\n"
2974 "Number of lines on screen (0 for no pausing)\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 vty->lines = lines;
2986
2987 return CMD_SUCCESS;
2988}
2989
2990DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2991 "terminal no length",
2992 "Set terminal line parameters\n"
2993 NO_STR
2994 "Set number of lines on a screen\n")
2995{
2996 vty->lines = -1;
2997 return CMD_SUCCESS;
2998}
2999
3000DEFUN (service_terminal_length, service_terminal_length_cmd,
3001 "service terminal-length <0-512>",
3002 "Set up miscellaneous service\n"
3003 "System wide terminal length configuration\n"
3004 "Number of lines of VTY (0 means no line control)\n")
3005{
3006 int lines;
3007 char *endptr = NULL;
3008
3009 lines = strtol (argv[0], &endptr, 10);
3010 if (lines < 0 || lines > 512 || *endptr != '\0')
3011 {
3012 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
3013 return CMD_WARNING;
3014 }
3015 host.lines = lines;
3016
3017 return CMD_SUCCESS;
3018}
3019
3020DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
3021 "no service terminal-length [<0-512>]",
3022 NO_STR
3023 "Set up miscellaneous service\n"
3024 "System wide terminal length configuration\n"
3025 "Number of lines of VTY (0 means no line control)\n")
3026{
3027 host.lines = -1;
3028 return CMD_SUCCESS;
3029}
3030
ajs2885f722004-12-17 23:16:33 +00003031DEFUN_HIDDEN (do_echo,
3032 echo_cmd,
3033 "echo .MESSAGE",
3034 "Echo a message back to the vty\n"
3035 "The message to echo\n")
3036{
3037 char *message;
3038
ajsf6834d42005-01-28 20:28:35 +00003039 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
3040 VTY_NEWLINE);
3041 if (message)
3042 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00003043 return CMD_SUCCESS;
3044}
3045
ajs274a4a42004-12-07 15:39:31 +00003046DEFUN (config_logmsg,
3047 config_logmsg_cmd,
3048 "logmsg "LOG_LEVELS" .MESSAGE",
3049 "Send a message to enabled logging destinations\n"
3050 LOG_LEVEL_DESC
3051 "The message to send\n")
3052{
3053 int level;
3054 char *message;
3055
3056 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3057 return CMD_ERR_NO_MATCH;
3058
Christian Hammersfc951862011-03-23 13:07:55 +03003059 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
ajsf6834d42005-01-28 20:28:35 +00003060 if (message)
3061 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00003062 return CMD_SUCCESS;
3063}
3064
3065DEFUN (show_logging,
3066 show_logging_cmd,
3067 "show logging",
3068 SHOW_STR
3069 "Show current logging configuration\n")
3070{
3071 struct zlog *zl = zlog_default;
3072
3073 vty_out (vty, "Syslog logging: ");
3074 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3075 vty_out (vty, "disabled");
3076 else
3077 vty_out (vty, "level %s, facility %s, ident %s",
3078 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3079 facility_name(zl->facility), zl->ident);
3080 vty_out (vty, "%s", VTY_NEWLINE);
3081
3082 vty_out (vty, "Stdout logging: ");
3083 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3084 vty_out (vty, "disabled");
3085 else
3086 vty_out (vty, "level %s",
3087 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3088 vty_out (vty, "%s", VTY_NEWLINE);
3089
3090 vty_out (vty, "Monitor logging: ");
3091 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3092 vty_out (vty, "disabled");
3093 else
3094 vty_out (vty, "level %s",
3095 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3096 vty_out (vty, "%s", VTY_NEWLINE);
3097
3098 vty_out (vty, "File logging: ");
3099 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3100 !zl->fp)
3101 vty_out (vty, "disabled");
3102 else
3103 vty_out (vty, "level %s, filename %s",
3104 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3105 zl->filename);
3106 vty_out (vty, "%s", VTY_NEWLINE);
3107
3108 vty_out (vty, "Protocol name: %s%s",
3109 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3110 vty_out (vty, "Record priority: %s%s",
3111 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003112 vty_out (vty, "Timestamp precision: %d%s",
3113 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003114
3115 return CMD_SUCCESS;
3116}
3117
paul718e3742002-12-13 20:15:29 +00003118DEFUN (config_log_stdout,
3119 config_log_stdout_cmd,
3120 "log stdout",
3121 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003122 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003123{
ajs274a4a42004-12-07 15:39:31 +00003124 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3125 return CMD_SUCCESS;
3126}
3127
3128DEFUN (config_log_stdout_level,
3129 config_log_stdout_level_cmd,
3130 "log stdout "LOG_LEVELS,
3131 "Logging control\n"
3132 "Set stdout logging level\n"
3133 LOG_LEVEL_DESC)
3134{
3135 int level;
3136
3137 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3138 return CMD_ERR_NO_MATCH;
3139 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003140 return CMD_SUCCESS;
3141}
3142
3143DEFUN (no_config_log_stdout,
3144 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003145 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003146 NO_STR
3147 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003148 "Cancel logging to stdout\n"
3149 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003150{
ajs274a4a42004-12-07 15:39:31 +00003151 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003152 return CMD_SUCCESS;
3153}
3154
ajs274a4a42004-12-07 15:39:31 +00003155DEFUN (config_log_monitor,
3156 config_log_monitor_cmd,
3157 "log monitor",
paul718e3742002-12-13 20:15:29 +00003158 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003159 "Set terminal line (monitor) logging level\n")
3160{
3161 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3162 return CMD_SUCCESS;
3163}
3164
3165DEFUN (config_log_monitor_level,
3166 config_log_monitor_level_cmd,
3167 "log monitor "LOG_LEVELS,
3168 "Logging control\n"
3169 "Set terminal line (monitor) logging level\n"
3170 LOG_LEVEL_DESC)
3171{
3172 int level;
3173
3174 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3175 return CMD_ERR_NO_MATCH;
3176 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3177 return CMD_SUCCESS;
3178}
3179
3180DEFUN (no_config_log_monitor,
3181 no_config_log_monitor_cmd,
3182 "no log monitor [LEVEL]",
3183 NO_STR
3184 "Logging control\n"
3185 "Disable terminal line (monitor) logging\n"
3186 "Logging level\n")
3187{
3188 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3189 return CMD_SUCCESS;
3190}
3191
3192static int
3193set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003194{
3195 int ret;
paul9035efa2004-10-10 11:56:56 +00003196 char *p = NULL;
3197 const char *fullpath;
3198
paul718e3742002-12-13 20:15:29 +00003199 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003200 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003201 {
paul9035efa2004-10-10 11:56:56 +00003202 char cwd[MAXPATHLEN+1];
3203 cwd[MAXPATHLEN] = '\0';
3204
3205 if (getcwd (cwd, MAXPATHLEN) == NULL)
3206 {
3207 zlog_err ("config_log_file: Unable to alloc mem!");
3208 return CMD_WARNING;
3209 }
3210
ajs274a4a42004-12-07 15:39:31 +00003211 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003212 == NULL)
3213 {
3214 zlog_err ("config_log_file: Unable to alloc mem!");
3215 return CMD_WARNING;
3216 }
ajs274a4a42004-12-07 15:39:31 +00003217 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003218 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003219 }
3220 else
ajs274a4a42004-12-07 15:39:31 +00003221 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003222
ajs274a4a42004-12-07 15:39:31 +00003223 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003224
paul9035efa2004-10-10 11:56:56 +00003225 if (p)
3226 XFREE (MTYPE_TMP, p);
3227
paul718e3742002-12-13 20:15:29 +00003228 if (!ret)
3229 {
ajs274a4a42004-12-07 15:39:31 +00003230 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003231 return CMD_WARNING;
3232 }
3233
3234 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003235 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003236
paul05865c92005-10-26 05:49:54 +00003237 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003238
3239 return CMD_SUCCESS;
3240}
3241
ajs274a4a42004-12-07 15:39:31 +00003242DEFUN (config_log_file,
3243 config_log_file_cmd,
3244 "log file FILENAME",
3245 "Logging control\n"
3246 "Logging to file\n"
3247 "Logging filename\n")
3248{
3249 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3250}
3251
3252DEFUN (config_log_file_level,
3253 config_log_file_level_cmd,
3254 "log file FILENAME "LOG_LEVELS,
3255 "Logging control\n"
3256 "Logging to file\n"
3257 "Logging filename\n"
3258 LOG_LEVEL_DESC)
3259{
3260 int level;
3261
3262 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3263 return CMD_ERR_NO_MATCH;
3264 return set_log_file(vty, argv[0], level);
3265}
3266
paul718e3742002-12-13 20:15:29 +00003267DEFUN (no_config_log_file,
3268 no_config_log_file_cmd,
3269 "no log file [FILENAME]",
3270 NO_STR
3271 "Logging control\n"
3272 "Cancel logging to file\n"
3273 "Logging file name\n")
3274{
3275 zlog_reset_file (NULL);
3276
3277 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003278 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003279
3280 host.logfile = NULL;
3281
3282 return CMD_SUCCESS;
3283}
3284
ajs274a4a42004-12-07 15:39:31 +00003285ALIAS (no_config_log_file,
3286 no_config_log_file_level_cmd,
3287 "no log file FILENAME LEVEL",
3288 NO_STR
3289 "Logging control\n"
3290 "Cancel logging to file\n"
3291 "Logging file name\n"
3292 "Logging level\n")
3293
paul718e3742002-12-13 20:15:29 +00003294DEFUN (config_log_syslog,
3295 config_log_syslog_cmd,
3296 "log syslog",
3297 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003298 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003299{
ajs274a4a42004-12-07 15:39:31 +00003300 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003301 return CMD_SUCCESS;
3302}
3303
ajs274a4a42004-12-07 15:39:31 +00003304DEFUN (config_log_syslog_level,
3305 config_log_syslog_level_cmd,
3306 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003307 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003308 "Set syslog logging level\n"
3309 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003310{
ajs274a4a42004-12-07 15:39:31 +00003311 int level;
paul12ab19f2003-07-26 06:14:55 +00003312
ajs274a4a42004-12-07 15:39:31 +00003313 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3314 return CMD_ERR_NO_MATCH;
3315 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3316 return CMD_SUCCESS;
3317}
paul12ab19f2003-07-26 06:14:55 +00003318
ajs274a4a42004-12-07 15:39:31 +00003319DEFUN_DEPRECATED (config_log_syslog_facility,
3320 config_log_syslog_facility_cmd,
3321 "log syslog facility "LOG_FACILITIES,
3322 "Logging control\n"
3323 "Logging goes to syslog\n"
3324 "(Deprecated) Facility parameter for syslog messages\n"
3325 LOG_FACILITY_DESC)
3326{
3327 int facility;
paul12ab19f2003-07-26 06:14:55 +00003328
ajs274a4a42004-12-07 15:39:31 +00003329 if ((facility = facility_match(argv[0])) < 0)
3330 return CMD_ERR_NO_MATCH;
3331
3332 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003333 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003334 return CMD_SUCCESS;
3335}
3336
3337DEFUN (no_config_log_syslog,
3338 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003339 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003340 NO_STR
3341 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003342 "Cancel logging to syslog\n"
3343 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003344{
ajs274a4a42004-12-07 15:39:31 +00003345 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003346 return CMD_SUCCESS;
3347}
3348
paul12ab19f2003-07-26 06:14:55 +00003349ALIAS (no_config_log_syslog,
3350 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003351 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003352 NO_STR
3353 "Logging control\n"
3354 "Logging goes to syslog\n"
3355 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003356 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003357
ajs274a4a42004-12-07 15:39:31 +00003358DEFUN (config_log_facility,
3359 config_log_facility_cmd,
3360 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003361 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003362 "Facility parameter for syslog messages\n"
3363 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003364{
ajs274a4a42004-12-07 15:39:31 +00003365 int facility;
3366
3367 if ((facility = facility_match(argv[0])) < 0)
3368 return CMD_ERR_NO_MATCH;
3369 zlog_default->facility = facility;
3370 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003371}
3372
ajs274a4a42004-12-07 15:39:31 +00003373DEFUN (no_config_log_facility,
3374 no_config_log_facility_cmd,
3375 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003376 NO_STR
3377 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003378 "Reset syslog facility to default (daemon)\n"
3379 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003380{
ajs274a4a42004-12-07 15:39:31 +00003381 zlog_default->facility = LOG_DAEMON;
3382 return CMD_SUCCESS;
3383}
3384
3385DEFUN_DEPRECATED (config_log_trap,
3386 config_log_trap_cmd,
3387 "log trap "LOG_LEVELS,
3388 "Logging control\n"
3389 "(Deprecated) Set logging level and default for all destinations\n"
3390 LOG_LEVEL_DESC)
3391{
3392 int new_level ;
3393 int i;
3394
3395 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3396 return CMD_ERR_NO_MATCH;
3397
3398 zlog_default->default_lvl = new_level;
3399 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3400 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3401 zlog_default->maxlvl[i] = new_level;
3402 return CMD_SUCCESS;
3403}
3404
3405DEFUN_DEPRECATED (no_config_log_trap,
3406 no_config_log_trap_cmd,
3407 "no log trap [LEVEL]",
3408 NO_STR
3409 "Logging control\n"
3410 "Permit all logging information\n"
3411 "Logging level\n")
3412{
3413 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003414 return CMD_SUCCESS;
3415}
3416
3417DEFUN (config_log_record_priority,
3418 config_log_record_priority_cmd,
3419 "log record-priority",
3420 "Logging control\n"
3421 "Log the priority of the message within the message\n")
3422{
3423 zlog_default->record_priority = 1 ;
3424 return CMD_SUCCESS;
3425}
3426
3427DEFUN (no_config_log_record_priority,
3428 no_config_log_record_priority_cmd,
3429 "no log record-priority",
3430 NO_STR
3431 "Logging control\n"
3432 "Do not log the priority of the message within the message\n")
3433{
3434 zlog_default->record_priority = 0 ;
3435 return CMD_SUCCESS;
3436}
3437
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003438DEFUN (config_log_timestamp_precision,
3439 config_log_timestamp_precision_cmd,
3440 "log timestamp precision <0-6>",
3441 "Logging control\n"
3442 "Timestamp configuration\n"
3443 "Set the timestamp precision\n"
3444 "Number of subsecond digits\n")
3445{
3446 if (argc != 1)
3447 {
3448 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3449 return CMD_WARNING;
3450 }
3451
3452 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3453 zlog_default->timestamp_precision, argv[0], 0, 6);
3454 return CMD_SUCCESS;
3455}
3456
3457DEFUN (no_config_log_timestamp_precision,
3458 no_config_log_timestamp_precision_cmd,
3459 "no log timestamp precision",
3460 NO_STR
3461 "Logging control\n"
3462 "Timestamp configuration\n"
3463 "Reset the timestamp precision to the default value of 0\n")
3464{
3465 zlog_default->timestamp_precision = 0 ;
3466 return CMD_SUCCESS;
3467}
3468
paul3b0c5d92005-03-08 10:43:43 +00003469DEFUN (banner_motd_file,
3470 banner_motd_file_cmd,
3471 "banner motd file [FILE]",
3472 "Set banner\n"
3473 "Banner for motd\n"
3474 "Banner from a file\n"
3475 "Filename\n")
3476{
paulb45da6f2005-03-08 15:16:57 +00003477 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003478 XFREE (MTYPE_HOST, host.motdfile);
3479 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003480
paul3b0c5d92005-03-08 10:43:43 +00003481 return CMD_SUCCESS;
3482}
paul718e3742002-12-13 20:15:29 +00003483
3484DEFUN (banner_motd_default,
3485 banner_motd_default_cmd,
3486 "banner motd default",
3487 "Set banner string\n"
3488 "Strings for motd\n"
3489 "Default string\n")
3490{
3491 host.motd = default_motd;
3492 return CMD_SUCCESS;
3493}
3494
3495DEFUN (no_banner_motd,
3496 no_banner_motd_cmd,
3497 "no banner motd",
3498 NO_STR
3499 "Set banner string\n"
3500 "Strings for motd\n")
3501{
3502 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003503 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003504 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003505 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003506 return CMD_SUCCESS;
3507}
3508
3509/* Set config filename. Called from vty.c */
3510void
3511host_config_set (char *filename)
3512{
Chris Caputo228da422009-07-18 05:44:03 +00003513 if (host.config)
3514 XFREE (MTYPE_HOST, host.config);
paul05865c92005-10-26 05:49:54 +00003515 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003516}
3517
3518void
3519install_default (enum node_type node)
3520{
3521 install_element (node, &config_exit_cmd);
3522 install_element (node, &config_quit_cmd);
3523 install_element (node, &config_end_cmd);
3524 install_element (node, &config_help_cmd);
3525 install_element (node, &config_list_cmd);
3526
3527 install_element (node, &config_write_terminal_cmd);
3528 install_element (node, &config_write_file_cmd);
3529 install_element (node, &config_write_memory_cmd);
3530 install_element (node, &config_write_cmd);
3531 install_element (node, &show_running_config_cmd);
3532}
3533
3534/* Initialize command interface. Install basic nodes and commands. */
3535void
3536cmd_init (int terminal)
3537{
Chris Caputo228da422009-07-18 05:44:03 +00003538 command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3539 desc_cr.cmd = command_cr;
3540 desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3541
paul718e3742002-12-13 20:15:29 +00003542 /* Allocate initial top vector of commands. */
3543 cmdvec = vector_init (VECTOR_MIN_SIZE);
3544
3545 /* Default host value settings. */
3546 host.name = NULL;
3547 host.password = NULL;
3548 host.enable = NULL;
3549 host.logfile = NULL;
3550 host.config = NULL;
3551 host.lines = -1;
3552 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003553 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003554
3555 /* Install top nodes. */
3556 install_node (&view_node, NULL);
3557 install_node (&enable_node, NULL);
3558 install_node (&auth_node, NULL);
3559 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01003560 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00003561 install_node (&config_node, config_write_host);
3562
3563 /* Each node's basic commands. */
3564 install_element (VIEW_NODE, &show_version_cmd);
3565 if (terminal)
3566 {
3567 install_element (VIEW_NODE, &config_list_cmd);
3568 install_element (VIEW_NODE, &config_exit_cmd);
3569 install_element (VIEW_NODE, &config_quit_cmd);
3570 install_element (VIEW_NODE, &config_help_cmd);
3571 install_element (VIEW_NODE, &config_enable_cmd);
3572 install_element (VIEW_NODE, &config_terminal_length_cmd);
3573 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003574 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003575 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003576
3577 install_element (RESTRICTED_NODE, &config_list_cmd);
3578 install_element (RESTRICTED_NODE, &config_exit_cmd);
3579 install_element (RESTRICTED_NODE, &config_quit_cmd);
3580 install_element (RESTRICTED_NODE, &config_help_cmd);
3581 install_element (RESTRICTED_NODE, &config_enable_cmd);
3582 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3583 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3584 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003585 }
3586
3587 if (terminal)
3588 {
3589 install_default (ENABLE_NODE);
3590 install_element (ENABLE_NODE, &config_disable_cmd);
3591 install_element (ENABLE_NODE, &config_terminal_cmd);
3592 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3593 }
3594 install_element (ENABLE_NODE, &show_startup_config_cmd);
3595 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003596
3597 if (terminal)
paul718e3742002-12-13 20:15:29 +00003598 {
hassoe7168df2004-10-03 20:11:32 +00003599 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3600 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003601 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003602 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003603 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003604
3605 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003606 }
3607
3608 install_element (CONFIG_NODE, &hostname_cmd);
3609 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003610
hassoea8e9d92004-10-07 21:32:14 +00003611 if (terminal)
3612 {
hassoe7168df2004-10-03 20:11:32 +00003613 install_element (CONFIG_NODE, &password_cmd);
3614 install_element (CONFIG_NODE, &password_text_cmd);
3615 install_element (CONFIG_NODE, &enable_password_cmd);
3616 install_element (CONFIG_NODE, &enable_password_text_cmd);
3617 install_element (CONFIG_NODE, &no_enable_password_cmd);
3618
paul718e3742002-12-13 20:15:29 +00003619 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003620 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003621 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003622 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3623 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3624 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003625 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003626 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003627 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003628 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003629 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003630 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003631 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003632 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003633 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003634 install_element (CONFIG_NODE, &config_log_facility_cmd);
3635 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003636 install_element (CONFIG_NODE, &config_log_trap_cmd);
3637 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3638 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3639 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003640 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3641 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003642 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3643 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3644 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003645 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003646 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3647 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3648 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003649
paul354d1192005-04-25 16:26:42 +00003650 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3651 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003652 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
Paul Jakmae276eb82010-01-09 16:15:00 +00003653
3654 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00003655 install_element (VIEW_NODE, &show_work_queues_cmd);
3656 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003657 }
paul718e3742002-12-13 20:15:29 +00003658 srand(time(NULL));
3659}
Chris Caputo228da422009-07-18 05:44:03 +00003660
3661void
3662cmd_terminate ()
3663{
3664 unsigned int i, j, k, l;
3665 struct cmd_node *cmd_node;
3666 struct cmd_element *cmd_element;
3667 struct desc *desc;
3668 vector cmd_node_v, cmd_element_v, desc_v;
3669
3670 if (cmdvec)
3671 {
3672 for (i = 0; i < vector_active (cmdvec); i++)
3673 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3674 {
3675 cmd_node_v = cmd_node->cmd_vector;
3676
3677 for (j = 0; j < vector_active (cmd_node_v); j++)
3678 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3679 cmd_element->strvec != NULL)
3680 {
3681 cmd_element_v = cmd_element->strvec;
3682
3683 for (k = 0; k < vector_active (cmd_element_v); k++)
3684 if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3685 {
3686 for (l = 0; l < vector_active (desc_v); l++)
3687 if ((desc = vector_slot (desc_v, l)) != NULL)
3688 {
3689 if (desc->cmd)
3690 XFREE (MTYPE_STRVEC, desc->cmd);
3691 if (desc->str)
3692 XFREE (MTYPE_STRVEC, desc->str);
3693
3694 XFREE (MTYPE_DESC, desc);
3695 }
3696 vector_free (desc_v);
3697 }
3698
3699 cmd_element->strvec = NULL;
3700 vector_free (cmd_element_v);
3701 }
3702
3703 vector_free (cmd_node_v);
3704 }
3705
3706 vector_free (cmdvec);
3707 cmdvec = NULL;
3708 }
3709
3710 if (command_cr)
3711 XFREE(MTYPE_STRVEC, command_cr);
3712 if (desc_cr.str)
3713 XFREE(MTYPE_STRVEC, desc_cr.str);
3714 if (host.name)
3715 XFREE (MTYPE_HOST, host.name);
3716 if (host.password)
3717 XFREE (MTYPE_HOST, host.password);
3718 if (host.password_encrypt)
3719 XFREE (MTYPE_HOST, host.password_encrypt);
3720 if (host.enable)
3721 XFREE (MTYPE_HOST, host.enable);
3722 if (host.enable_encrypt)
3723 XFREE (MTYPE_HOST, host.enable_encrypt);
3724 if (host.logfile)
3725 XFREE (MTYPE_HOST, host.logfile);
3726 if (host.motdfile)
3727 XFREE (MTYPE_HOST, host.motdfile);
3728 if (host.config)
3729 XFREE (MTYPE_HOST, host.config);
3730}