blob: 64563b5d0265debddd87bb77cb178bbc3b4b5f34 [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
Roman Hoog Antink7c9c6ae2012-05-09 06:35:34 +0000871 return no_match;
paul718e3742002-12-13 20:15:29 +0000872}
873
ajs274a4a42004-12-07 15:39:31 +0000874static enum match_type
hasso8c328f12004-10-05 21:01:23 +0000875cmd_ipv6_prefix_match (const char *str)
paul718e3742002-12-13 20:15:29 +0000876{
877 int state = STATE_START;
878 int colons = 0, nums = 0, double_colon = 0;
879 int mask;
hasso8c328f12004-10-05 21:01:23 +0000880 const char *sp = NULL;
paul718e3742002-12-13 20:15:29 +0000881 char *endptr = NULL;
882
883 if (str == NULL)
884 return partly_match;
885
886 if (strspn (str, IPV6_PREFIX_STR) != strlen (str))
887 return no_match;
888
889 while (*str != '\0' && state != STATE_MASK)
890 {
891 switch (state)
892 {
893 case STATE_START:
894 if (*str == ':')
895 {
896 if (*(str + 1) != ':' && *(str + 1) != '\0')
897 return no_match;
898 colons--;
899 state = STATE_COLON;
900 }
901 else
902 {
903 sp = str;
904 state = STATE_ADDR;
905 }
906
907 continue;
908 case STATE_COLON:
909 colons++;
910 if (*(str + 1) == '/')
911 return no_match;
912 else if (*(str + 1) == ':')
913 state = STATE_DOUBLE;
914 else
915 {
916 sp = str + 1;
917 state = STATE_ADDR;
918 }
919 break;
920 case STATE_DOUBLE:
921 if (double_colon)
922 return no_match;
923
924 if (*(str + 1) == ':')
925 return no_match;
926 else
927 {
928 if (*(str + 1) != '\0' && *(str + 1) != '/')
929 colons++;
930 sp = str + 1;
931
932 if (*(str + 1) == '/')
933 state = STATE_SLASH;
934 else
935 state = STATE_ADDR;
936 }
937
938 double_colon++;
939 nums += 1;
940 break;
941 case STATE_ADDR:
942 if (*(str + 1) == ':' || *(str + 1) == '.'
943 || *(str + 1) == '\0' || *(str + 1) == '/')
944 {
945 if (str - sp > 3)
946 return no_match;
947
948 for (; sp <= str; sp++)
949 if (*sp == '/')
950 return no_match;
951
952 nums++;
953
954 if (*(str + 1) == ':')
955 state = STATE_COLON;
956 else if (*(str + 1) == '.')
David Lamparteraa5cf242012-07-19 16:11:50 +0200957 {
958 if (colons || double_colon)
959 state = STATE_DOT;
960 else
961 return no_match;
962 }
paul718e3742002-12-13 20:15:29 +0000963 else if (*(str + 1) == '/')
964 state = STATE_SLASH;
965 }
966 break;
967 case STATE_DOT:
968 state = STATE_ADDR;
969 break;
970 case STATE_SLASH:
971 if (*(str + 1) == '\0')
972 return partly_match;
973
974 state = STATE_MASK;
975 break;
976 default:
977 break;
978 }
979
980 if (nums > 11)
981 return no_match;
982
983 if (colons > 7)
984 return no_match;
985
986 str++;
987 }
988
989 if (state < STATE_MASK)
990 return partly_match;
991
992 mask = strtol (str, &endptr, 10);
993 if (*endptr != '\0')
994 return no_match;
995
996 if (mask < 0 || mask > 128)
997 return no_match;
998
999/* I don't know why mask < 13 makes command match partly.
1000 Forgive me to make this comments. I Want to set static default route
1001 because of lack of function to originate default in ospf6d; sorry
1002 yasu
1003 if (mask < 13)
1004 return partly_match;
1005*/
1006
1007 return exact_match;
1008}
1009
paul22e0a9e2003-07-11 17:55:46 +00001010#endif /* HAVE_IPV6 */
1011
paul718e3742002-12-13 20:15:29 +00001012#define DECIMAL_STRLEN_MAX 10
1013
ajs274a4a42004-12-07 15:39:31 +00001014static int
hasso8c328f12004-10-05 21:01:23 +00001015cmd_range_match (const char *range, const char *str)
paul718e3742002-12-13 20:15:29 +00001016{
1017 char *p;
1018 char buf[DECIMAL_STRLEN_MAX + 1];
1019 char *endptr = NULL;
1020 unsigned long min, max, val;
1021
1022 if (str == NULL)
1023 return 1;
1024
1025 val = strtoul (str, &endptr, 10);
1026 if (*endptr != '\0')
1027 return 0;
1028
1029 range++;
1030 p = strchr (range, '-');
1031 if (p == NULL)
1032 return 0;
1033 if (p - range > DECIMAL_STRLEN_MAX)
1034 return 0;
1035 strncpy (buf, range, p - range);
1036 buf[p - range] = '\0';
1037 min = strtoul (buf, &endptr, 10);
1038 if (*endptr != '\0')
1039 return 0;
1040
1041 range = p + 1;
1042 p = strchr (range, '>');
1043 if (p == NULL)
1044 return 0;
1045 if (p - range > DECIMAL_STRLEN_MAX)
1046 return 0;
1047 strncpy (buf, range, p - range);
1048 buf[p - range] = '\0';
1049 max = strtoul (buf, &endptr, 10);
1050 if (*endptr != '\0')
1051 return 0;
1052
1053 if (val < min || val > max)
1054 return 0;
1055
1056 return 1;
1057}
1058
1059/* Make completion match and return match type flag. */
ajs274a4a42004-12-07 15:39:31 +00001060static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001061cmd_filter_by_completion (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001062{
hasso8c328f12004-10-05 21:01:23 +00001063 unsigned int i;
1064 const char *str;
paul718e3742002-12-13 20:15:29 +00001065 struct cmd_element *cmd_element;
1066 enum match_type match_type;
1067 vector descvec;
1068 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001069
paul718e3742002-12-13 20:15:29 +00001070 match_type = no_match;
1071
1072 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001073 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001074 if ((cmd_element = vector_slot (v, i)) != NULL)
1075 {
paul55468c82005-03-14 20:19:01 +00001076 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001077 vector_slot (v, i) = NULL;
1078 else
1079 {
hasso8c328f12004-10-05 21:01:23 +00001080 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001081 int matched = 0;
1082
1083 descvec = vector_slot (cmd_element->strvec, index);
paul909a2152005-03-14 17:41:45 +00001084
paul55468c82005-03-14 20:19:01 +00001085 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001086 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001087 {
1088 str = desc->cmd;
1089
1090 if (CMD_VARARG (str))
1091 {
1092 if (match_type < vararg_match)
1093 match_type = vararg_match;
1094 matched++;
1095 }
1096 else if (CMD_RANGE (str))
1097 {
1098 if (cmd_range_match (str, command))
1099 {
1100 if (match_type < range_match)
1101 match_type = range_match;
paul718e3742002-12-13 20:15:29 +00001102
paul909a2152005-03-14 17:41:45 +00001103 matched++;
1104 }
1105 }
paul22e0a9e2003-07-11 17:55:46 +00001106#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001107 else if (CMD_IPV6 (str))
1108 {
1109 if (cmd_ipv6_match (command))
1110 {
1111 if (match_type < ipv6_match)
1112 match_type = ipv6_match;
paul718e3742002-12-13 20:15:29 +00001113
paul909a2152005-03-14 17:41:45 +00001114 matched++;
1115 }
1116 }
1117 else if (CMD_IPV6_PREFIX (str))
1118 {
1119 if (cmd_ipv6_prefix_match (command))
1120 {
1121 if (match_type < ipv6_prefix_match)
1122 match_type = ipv6_prefix_match;
paul718e3742002-12-13 20:15:29 +00001123
paul909a2152005-03-14 17:41:45 +00001124 matched++;
1125 }
1126 }
1127#endif /* HAVE_IPV6 */
1128 else if (CMD_IPV4 (str))
1129 {
1130 if (cmd_ipv4_match (command))
1131 {
1132 if (match_type < ipv4_match)
1133 match_type = ipv4_match;
paul718e3742002-12-13 20:15:29 +00001134
paul909a2152005-03-14 17:41:45 +00001135 matched++;
1136 }
1137 }
1138 else if (CMD_IPV4_PREFIX (str))
1139 {
1140 if (cmd_ipv4_prefix_match (command))
1141 {
1142 if (match_type < ipv4_prefix_match)
1143 match_type = ipv4_prefix_match;
1144 matched++;
1145 }
1146 }
1147 else
1148 /* Check is this point's argument optional ? */
1149 if (CMD_OPTION (str) || CMD_VARIABLE (str))
1150 {
1151 if (match_type < extend_match)
1152 match_type = extend_match;
1153 matched++;
1154 }
1155 else if (strncmp (command, str, strlen (command)) == 0)
1156 {
1157 if (strcmp (command, str) == 0)
1158 match_type = exact_match;
1159 else
1160 {
1161 if (match_type < partly_match)
1162 match_type = partly_match;
1163 }
1164 matched++;
1165 }
1166 }
1167 if (!matched)
paul718e3742002-12-13 20:15:29 +00001168 vector_slot (v, i) = NULL;
1169 }
1170 }
1171 return match_type;
1172}
1173
1174/* Filter vector by command character with index. */
ajs274a4a42004-12-07 15:39:31 +00001175static enum match_type
hasso8c328f12004-10-05 21:01:23 +00001176cmd_filter_by_string (char *command, vector v, unsigned int index)
paul718e3742002-12-13 20:15:29 +00001177{
hasso8c328f12004-10-05 21:01:23 +00001178 unsigned int i;
1179 const char *str;
paul718e3742002-12-13 20:15:29 +00001180 struct cmd_element *cmd_element;
1181 enum match_type match_type;
1182 vector descvec;
1183 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001184
paul718e3742002-12-13 20:15:29 +00001185 match_type = no_match;
1186
1187 /* If command and cmd_element string does not match set NULL to vector */
paul55468c82005-03-14 20:19:01 +00001188 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001189 if ((cmd_element = vector_slot (v, i)) != NULL)
1190 {
1191 /* If given index is bigger than max string vector of command,
paul909a2152005-03-14 17:41:45 +00001192 set NULL */
paul55468c82005-03-14 20:19:01 +00001193 if (index >= vector_active (cmd_element->strvec))
paul718e3742002-12-13 20:15:29 +00001194 vector_slot (v, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001195 else
paul718e3742002-12-13 20:15:29 +00001196 {
hasso8c328f12004-10-05 21:01:23 +00001197 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001198 int matched = 0;
1199
1200 descvec = vector_slot (cmd_element->strvec, index);
1201
paul55468c82005-03-14 20:19:01 +00001202 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001203 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001204 {
1205 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001206
paul909a2152005-03-14 17:41:45 +00001207 if (CMD_VARARG (str))
1208 {
1209 if (match_type < vararg_match)
1210 match_type = vararg_match;
1211 matched++;
1212 }
1213 else if (CMD_RANGE (str))
1214 {
1215 if (cmd_range_match (str, command))
1216 {
1217 if (match_type < range_match)
1218 match_type = range_match;
1219 matched++;
1220 }
1221 }
paul22e0a9e2003-07-11 17:55:46 +00001222#ifdef HAVE_IPV6
paul909a2152005-03-14 17:41:45 +00001223 else if (CMD_IPV6 (str))
1224 {
1225 if (cmd_ipv6_match (command) == exact_match)
1226 {
1227 if (match_type < ipv6_match)
1228 match_type = ipv6_match;
1229 matched++;
1230 }
1231 }
1232 else if (CMD_IPV6_PREFIX (str))
1233 {
1234 if (cmd_ipv6_prefix_match (command) == exact_match)
1235 {
1236 if (match_type < ipv6_prefix_match)
1237 match_type = ipv6_prefix_match;
1238 matched++;
1239 }
1240 }
paul22e0a9e2003-07-11 17:55:46 +00001241#endif /* HAVE_IPV6 */
paul909a2152005-03-14 17:41:45 +00001242 else if (CMD_IPV4 (str))
1243 {
1244 if (cmd_ipv4_match (command) == exact_match)
1245 {
1246 if (match_type < ipv4_match)
1247 match_type = ipv4_match;
1248 matched++;
1249 }
1250 }
1251 else if (CMD_IPV4_PREFIX (str))
1252 {
1253 if (cmd_ipv4_prefix_match (command) == exact_match)
1254 {
1255 if (match_type < ipv4_prefix_match)
1256 match_type = ipv4_prefix_match;
1257 matched++;
1258 }
1259 }
1260 else if (CMD_OPTION (str) || CMD_VARIABLE (str))
1261 {
1262 if (match_type < extend_match)
1263 match_type = extend_match;
1264 matched++;
1265 }
1266 else
1267 {
1268 if (strcmp (command, str) == 0)
1269 {
1270 match_type = exact_match;
1271 matched++;
1272 }
1273 }
1274 }
1275 if (!matched)
paul718e3742002-12-13 20:15:29 +00001276 vector_slot (v, i) = NULL;
1277 }
1278 }
1279 return match_type;
1280}
1281
1282/* Check ambiguous match */
ajs274a4a42004-12-07 15:39:31 +00001283static int
paul718e3742002-12-13 20:15:29 +00001284is_cmd_ambiguous (char *command, vector v, int index, enum match_type type)
1285{
hasso8c328f12004-10-05 21:01:23 +00001286 unsigned int i;
1287 unsigned int j;
1288 const char *str = NULL;
paul718e3742002-12-13 20:15:29 +00001289 struct cmd_element *cmd_element;
hasso8c328f12004-10-05 21:01:23 +00001290 const char *matched = NULL;
paul718e3742002-12-13 20:15:29 +00001291 vector descvec;
1292 struct desc *desc;
paul909a2152005-03-14 17:41:45 +00001293
paul55468c82005-03-14 20:19:01 +00001294 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001295 if ((cmd_element = vector_slot (v, i)) != NULL)
1296 {
1297 int match = 0;
1298
1299 descvec = vector_slot (cmd_element->strvec, index);
1300
paul55468c82005-03-14 20:19:01 +00001301 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001302 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001303 {
1304 enum match_type ret;
1305
1306 str = desc->cmd;
paul718e3742002-12-13 20:15:29 +00001307
paul909a2152005-03-14 17:41:45 +00001308 switch (type)
1309 {
1310 case exact_match:
1311 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1312 && strcmp (command, str) == 0)
1313 match++;
1314 break;
1315 case partly_match:
1316 if (!(CMD_OPTION (str) || CMD_VARIABLE (str))
1317 && strncmp (command, str, strlen (command)) == 0)
1318 {
1319 if (matched && strcmp (matched, str) != 0)
1320 return 1; /* There is ambiguous match. */
1321 else
1322 matched = str;
1323 match++;
1324 }
1325 break;
1326 case range_match:
1327 if (cmd_range_match (str, command))
1328 {
1329 if (matched && strcmp (matched, str) != 0)
1330 return 1;
1331 else
1332 matched = str;
1333 match++;
1334 }
1335 break;
1336#ifdef HAVE_IPV6
1337 case ipv6_match:
1338 if (CMD_IPV6 (str))
1339 match++;
1340 break;
1341 case ipv6_prefix_match:
1342 if ((ret = cmd_ipv6_prefix_match (command)) != no_match)
1343 {
1344 if (ret == partly_match)
1345 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001346
paul909a2152005-03-14 17:41:45 +00001347 match++;
1348 }
1349 break;
1350#endif /* HAVE_IPV6 */
1351 case ipv4_match:
1352 if (CMD_IPV4 (str))
paul718e3742002-12-13 20:15:29 +00001353 match++;
paul909a2152005-03-14 17:41:45 +00001354 break;
1355 case ipv4_prefix_match:
1356 if ((ret = cmd_ipv4_prefix_match (command)) != no_match)
1357 {
1358 if (ret == partly_match)
1359 return 2; /* There is incomplete match. */
paul718e3742002-12-13 20:15:29 +00001360
paul909a2152005-03-14 17:41:45 +00001361 match++;
1362 }
1363 break;
1364 case extend_match:
1365 if (CMD_OPTION (str) || CMD_VARIABLE (str))
paul718e3742002-12-13 20:15:29 +00001366 match++;
paul909a2152005-03-14 17:41:45 +00001367 break;
1368 case no_match:
1369 default:
1370 break;
1371 }
1372 }
1373 if (!match)
paul718e3742002-12-13 20:15:29 +00001374 vector_slot (v, i) = NULL;
1375 }
1376 return 0;
1377}
1378
1379/* If src matches dst return dst string, otherwise return NULL */
ajs274a4a42004-12-07 15:39:31 +00001380static const char *
hasso8c328f12004-10-05 21:01:23 +00001381cmd_entry_function (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001382{
1383 /* Skip variable arguments. */
1384 if (CMD_OPTION (dst) || CMD_VARIABLE (dst) || CMD_VARARG (dst) ||
1385 CMD_IPV4 (dst) || CMD_IPV4_PREFIX (dst) || CMD_RANGE (dst))
1386 return NULL;
1387
1388 /* In case of 'command \t', given src is NULL string. */
1389 if (src == NULL)
1390 return dst;
1391
1392 /* Matched with input string. */
1393 if (strncmp (src, dst, strlen (src)) == 0)
1394 return dst;
1395
1396 return NULL;
1397}
1398
1399/* If src matches dst return dst string, otherwise return NULL */
1400/* This version will return the dst string always if it is
1401 CMD_VARIABLE for '?' key processing */
ajs274a4a42004-12-07 15:39:31 +00001402static const char *
hasso8c328f12004-10-05 21:01:23 +00001403cmd_entry_function_desc (const char *src, const char *dst)
paul718e3742002-12-13 20:15:29 +00001404{
1405 if (CMD_VARARG (dst))
1406 return dst;
1407
1408 if (CMD_RANGE (dst))
1409 {
1410 if (cmd_range_match (dst, src))
1411 return dst;
1412 else
1413 return NULL;
1414 }
1415
paul22e0a9e2003-07-11 17:55:46 +00001416#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +00001417 if (CMD_IPV6 (dst))
1418 {
1419 if (cmd_ipv6_match (src))
1420 return dst;
1421 else
1422 return NULL;
1423 }
1424
1425 if (CMD_IPV6_PREFIX (dst))
1426 {
1427 if (cmd_ipv6_prefix_match (src))
1428 return dst;
1429 else
1430 return NULL;
1431 }
paul22e0a9e2003-07-11 17:55:46 +00001432#endif /* HAVE_IPV6 */
paul718e3742002-12-13 20:15:29 +00001433
1434 if (CMD_IPV4 (dst))
1435 {
1436 if (cmd_ipv4_match (src))
1437 return dst;
1438 else
1439 return NULL;
1440 }
1441
1442 if (CMD_IPV4_PREFIX (dst))
1443 {
1444 if (cmd_ipv4_prefix_match (src))
1445 return dst;
1446 else
1447 return NULL;
1448 }
1449
1450 /* Optional or variable commands always match on '?' */
1451 if (CMD_OPTION (dst) || CMD_VARIABLE (dst))
1452 return dst;
1453
1454 /* In case of 'command \t', given src is NULL string. */
1455 if (src == NULL)
1456 return dst;
1457
1458 if (strncmp (src, dst, strlen (src)) == 0)
1459 return dst;
1460 else
1461 return NULL;
1462}
1463
1464/* Check same string element existence. If it isn't there return
1465 1. */
ajs274a4a42004-12-07 15:39:31 +00001466static int
hasso8c328f12004-10-05 21:01:23 +00001467cmd_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001468{
hasso8c328f12004-10-05 21:01:23 +00001469 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001470 char *match;
1471
paul55468c82005-03-14 20:19:01 +00001472 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001473 if ((match = vector_slot (v, i)) != NULL)
1474 if (strcmp (match, str) == 0)
1475 return 0;
1476 return 1;
1477}
1478
1479/* Compare string to description vector. If there is same string
1480 return 1 else return 0. */
ajs274a4a42004-12-07 15:39:31 +00001481static int
hasso8c328f12004-10-05 21:01:23 +00001482desc_unique_string (vector v, const char *str)
paul718e3742002-12-13 20:15:29 +00001483{
hasso8c328f12004-10-05 21:01:23 +00001484 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001485 struct desc *desc;
1486
paul55468c82005-03-14 20:19:01 +00001487 for (i = 0; i < vector_active (v); i++)
paul718e3742002-12-13 20:15:29 +00001488 if ((desc = vector_slot (v, i)) != NULL)
1489 if (strcmp (desc->cmd, str) == 0)
1490 return 1;
1491 return 0;
1492}
1493
ajs274a4a42004-12-07 15:39:31 +00001494static int
paulb92938a2002-12-13 21:20:42 +00001495cmd_try_do_shortcut (enum node_type node, char* first_word) {
1496 if ( first_word != NULL &&
1497 node != AUTH_NODE &&
1498 node != VIEW_NODE &&
1499 node != AUTH_ENABLE_NODE &&
1500 node != ENABLE_NODE &&
Paul Jakma62687ff2008-08-23 14:27:06 +01001501 node != RESTRICTED_NODE &&
paulb92938a2002-12-13 21:20:42 +00001502 0 == strcmp( "do", first_word ) )
1503 return 1;
1504 return 0;
1505}
1506
paul718e3742002-12-13 20:15:29 +00001507/* '?' describe command support. */
ajs274a4a42004-12-07 15:39:31 +00001508static vector
paulb92938a2002-12-13 21:20:42 +00001509cmd_describe_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001510{
paulb8961472005-03-14 17:35:52 +00001511 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001512 vector cmd_vector;
1513#define INIT_MATCHVEC_SIZE 10
1514 vector matchvec;
1515 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001516 unsigned int index;
paul54aba542003-08-21 20:28:24 +00001517 int ret;
1518 enum match_type match;
1519 char *command;
paul718e3742002-12-13 20:15:29 +00001520
1521 /* Set index. */
paul55468c82005-03-14 20:19:01 +00001522 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001523 {
1524 *status = CMD_ERR_NO_MATCH;
1525 return NULL;
1526 }
1527 else
paul55468c82005-03-14 20:19:01 +00001528 index = vector_active (vline) - 1;
paul909a2152005-03-14 17:41:45 +00001529
paul718e3742002-12-13 20:15:29 +00001530 /* Make copy vector of current node's command vector. */
1531 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1532
1533 /* Prepare match vector */
1534 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1535
1536 /* Filter commands. */
paul54aba542003-08-21 20:28:24 +00001537 /* Only words precedes current word will be checked in this loop. */
paul718e3742002-12-13 20:15:29 +00001538 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001539 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001540 {
1541 match = cmd_filter_by_completion (command, cmd_vector, i);
1542
1543 if (match == vararg_match)
1544 {
1545 struct cmd_element *cmd_element;
1546 vector descvec;
1547 unsigned int j, k;
paul718e3742002-12-13 20:15:29 +00001548
paul55468c82005-03-14 20:19:01 +00001549 for (j = 0; j < vector_active (cmd_vector); j++)
paulb8961472005-03-14 17:35:52 +00001550 if ((cmd_element = vector_slot (cmd_vector, j)) != NULL
paul55468c82005-03-14 20:19:01 +00001551 && (vector_active (cmd_element->strvec)))
paul909a2152005-03-14 17:41:45 +00001552 {
1553 descvec = vector_slot (cmd_element->strvec,
paul55468c82005-03-14 20:19:01 +00001554 vector_active (cmd_element->strvec) - 1);
1555 for (k = 0; k < vector_active (descvec); k++)
paul909a2152005-03-14 17:41:45 +00001556 {
1557 struct desc *desc = vector_slot (descvec, k);
1558 vector_set (matchvec, desc);
1559 }
1560 }
1561
1562 vector_set (matchvec, &desc_cr);
1563 vector_free (cmd_vector);
paul718e3742002-12-13 20:15:29 +00001564
paul909a2152005-03-14 17:41:45 +00001565 return matchvec;
1566 }
paul718e3742002-12-13 20:15:29 +00001567
paul909a2152005-03-14 17:41:45 +00001568 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1569 {
1570 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001571 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001572 *status = CMD_ERR_AMBIGUOUS;
1573 return NULL;
1574 }
1575 else if (ret == 2)
1576 {
1577 vector_free (cmd_vector);
Paul Jakmae5cd7062006-06-15 12:25:55 +00001578 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001579 *status = CMD_ERR_NO_MATCH;
1580 return NULL;
1581 }
1582 }
paul718e3742002-12-13 20:15:29 +00001583
1584 /* Prepare match vector */
1585 /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
1586
paul54aba542003-08-21 20:28:24 +00001587 /* Make sure that cmd_vector is filtered based on current word */
1588 command = vector_slot (vline, index);
1589 if (command)
1590 match = cmd_filter_by_completion (command, cmd_vector, index);
1591
paul718e3742002-12-13 20:15:29 +00001592 /* Make description vector. */
paul55468c82005-03-14 20:19:01 +00001593 for (i = 0; i < vector_active (cmd_vector); i++)
paul718e3742002-12-13 20:15:29 +00001594 if ((cmd_element = vector_slot (cmd_vector, i)) != NULL)
1595 {
paul718e3742002-12-13 20:15:29 +00001596 vector strvec = cmd_element->strvec;
1597
paul55468c82005-03-14 20:19:01 +00001598 /* if command is NULL, index may be equal to vector_active */
1599 if (command && index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001600 vector_slot (cmd_vector, i) = NULL;
1601 else
1602 {
paul54aba542003-08-21 20:28:24 +00001603 /* Check if command is completed. */
paul55468c82005-03-14 20:19:01 +00001604 if (command == NULL && index == vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001605 {
Chris Caputo228da422009-07-18 05:44:03 +00001606 if (!desc_unique_string (matchvec, command_cr))
paul718e3742002-12-13 20:15:29 +00001607 vector_set (matchvec, &desc_cr);
1608 }
1609 else
1610 {
hasso8c328f12004-10-05 21:01:23 +00001611 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001612 vector descvec = vector_slot (strvec, index);
1613 struct desc *desc;
1614
paul55468c82005-03-14 20:19:01 +00001615 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001616 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001617 {
Chris Caputo228da422009-07-18 05:44:03 +00001618 const char *string;
1619
paul909a2152005-03-14 17:41:45 +00001620 string = cmd_entry_function_desc (command, desc->cmd);
1621 if (string)
1622 {
1623 /* Uniqueness check */
1624 if (!desc_unique_string (matchvec, string))
1625 vector_set (matchvec, desc);
1626 }
1627 }
paul718e3742002-12-13 20:15:29 +00001628 }
1629 }
1630 }
1631 vector_free (cmd_vector);
1632
1633 if (vector_slot (matchvec, 0) == NULL)
1634 {
1635 vector_free (matchvec);
paul909a2152005-03-14 17:41:45 +00001636 *status = CMD_ERR_NO_MATCH;
Paul Jakma5fc60512006-05-12 23:24:09 +00001637 return NULL;
paul718e3742002-12-13 20:15:29 +00001638 }
paul718e3742002-12-13 20:15:29 +00001639
Paul Jakma5fc60512006-05-12 23:24:09 +00001640 *status = CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00001641 return matchvec;
1642}
1643
paulb92938a2002-12-13 21:20:42 +00001644vector
1645cmd_describe_command (vector vline, struct vty *vty, int *status)
1646{
1647 vector ret;
1648
1649 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1650 {
1651 enum node_type onode;
1652 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001653 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001654
1655 onode = vty->node;
1656 vty->node = ENABLE_NODE;
1657 /* We can try it on enable node, cos' the vty is authenticated */
1658
1659 shifted_vline = vector_init (vector_count(vline));
1660 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001661 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001662 {
1663 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1664 }
1665
1666 ret = cmd_describe_command_real (shifted_vline, vty, status);
1667
1668 vector_free(shifted_vline);
1669 vty->node = onode;
1670 return ret;
1671 }
1672
1673
1674 return cmd_describe_command_real (vline, vty, status);
1675}
1676
1677
paul718e3742002-12-13 20:15:29 +00001678/* Check LCD of matched command. */
ajs274a4a42004-12-07 15:39:31 +00001679static int
paul718e3742002-12-13 20:15:29 +00001680cmd_lcd (char **matched)
1681{
1682 int i;
1683 int j;
1684 int lcd = -1;
1685 char *s1, *s2;
1686 char c1, c2;
1687
1688 if (matched[0] == NULL || matched[1] == NULL)
1689 return 0;
1690
1691 for (i = 1; matched[i] != NULL; i++)
1692 {
1693 s1 = matched[i - 1];
1694 s2 = matched[i];
1695
1696 for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
1697 if (c1 != c2)
1698 break;
1699
1700 if (lcd < 0)
1701 lcd = j;
1702 else
1703 {
1704 if (lcd > j)
1705 lcd = j;
1706 }
1707 }
1708 return lcd;
1709}
1710
1711/* Command line completion support. */
ajs274a4a42004-12-07 15:39:31 +00001712static char **
paulb92938a2002-12-13 21:20:42 +00001713cmd_complete_command_real (vector vline, struct vty *vty, int *status)
paul718e3742002-12-13 20:15:29 +00001714{
paulb8961472005-03-14 17:35:52 +00001715 unsigned int i;
paul718e3742002-12-13 20:15:29 +00001716 vector cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1717#define INIT_MATCHVEC_SIZE 10
1718 vector matchvec;
1719 struct cmd_element *cmd_element;
paulb8961472005-03-14 17:35:52 +00001720 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001721 char **match_str;
1722 struct desc *desc;
1723 vector descvec;
1724 char *command;
1725 int lcd;
1726
paul55468c82005-03-14 20:19:01 +00001727 if (vector_active (vline) == 0)
paulb8961472005-03-14 17:35:52 +00001728 {
Paul Jakmad2519962006-05-12 23:19:37 +00001729 vector_free (cmd_vector);
paulb8961472005-03-14 17:35:52 +00001730 *status = CMD_ERR_NO_MATCH;
1731 return NULL;
1732 }
1733 else
paul55468c82005-03-14 20:19:01 +00001734 index = vector_active (vline) - 1;
paulb8961472005-03-14 17:35:52 +00001735
paul718e3742002-12-13 20:15:29 +00001736 /* First, filter by preceeding command string */
1737 for (i = 0; i < index; i++)
paulb8961472005-03-14 17:35:52 +00001738 if ((command = vector_slot (vline, i)))
paul909a2152005-03-14 17:41:45 +00001739 {
1740 enum match_type match;
1741 int ret;
paul718e3742002-12-13 20:15:29 +00001742
paul909a2152005-03-14 17:41:45 +00001743 /* First try completion match, if there is exactly match return 1 */
1744 match = cmd_filter_by_completion (command, cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00001745
paul909a2152005-03-14 17:41:45 +00001746 /* If there is exact match then filter ambiguous match else check
1747 ambiguousness. */
1748 if ((ret = is_cmd_ambiguous (command, cmd_vector, i, match)) == 1)
1749 {
1750 vector_free (cmd_vector);
1751 *status = CMD_ERR_AMBIGUOUS;
1752 return NULL;
1753 }
1754 /*
1755 else if (ret == 2)
1756 {
1757 vector_free (cmd_vector);
1758 *status = CMD_ERR_NO_MATCH;
1759 return NULL;
1760 }
1761 */
1762 }
1763
paul718e3742002-12-13 20:15:29 +00001764 /* Prepare match vector. */
1765 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1766
1767 /* Now we got into completion */
paul55468c82005-03-14 20:19:01 +00001768 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001769 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001770 {
hasso8c328f12004-10-05 21:01:23 +00001771 const char *string;
paul718e3742002-12-13 20:15:29 +00001772 vector strvec = cmd_element->strvec;
paul909a2152005-03-14 17:41:45 +00001773
paul718e3742002-12-13 20:15:29 +00001774 /* Check field length */
paul55468c82005-03-14 20:19:01 +00001775 if (index >= vector_active (strvec))
paul718e3742002-12-13 20:15:29 +00001776 vector_slot (cmd_vector, i) = NULL;
paul909a2152005-03-14 17:41:45 +00001777 else
paul718e3742002-12-13 20:15:29 +00001778 {
hasso8c328f12004-10-05 21:01:23 +00001779 unsigned int j;
paul718e3742002-12-13 20:15:29 +00001780
1781 descvec = vector_slot (strvec, index);
paul55468c82005-03-14 20:19:01 +00001782 for (j = 0; j < vector_active (descvec); j++)
paulb8961472005-03-14 17:35:52 +00001783 if ((desc = vector_slot (descvec, j)))
paul909a2152005-03-14 17:41:45 +00001784 {
paulb8961472005-03-14 17:35:52 +00001785 if ((string =
1786 cmd_entry_function (vector_slot (vline, index),
paul909a2152005-03-14 17:41:45 +00001787 desc->cmd)))
1788 if (cmd_unique_string (matchvec, string))
1789 vector_set (matchvec, XSTRDUP (MTYPE_TMP, string));
1790 }
paul718e3742002-12-13 20:15:29 +00001791 }
1792 }
1793
1794 /* We don't need cmd_vector any more. */
1795 vector_free (cmd_vector);
1796
1797 /* No matched command */
1798 if (vector_slot (matchvec, 0) == NULL)
1799 {
1800 vector_free (matchvec);
1801
1802 /* In case of 'command \t' pattern. Do you need '?' command at
1803 the end of the line. */
1804 if (vector_slot (vline, index) == '\0')
1805 *status = CMD_ERR_NOTHING_TODO;
1806 else
1807 *status = CMD_ERR_NO_MATCH;
1808 return NULL;
1809 }
1810
1811 /* Only one matched */
1812 if (vector_slot (matchvec, 1) == NULL)
1813 {
1814 match_str = (char **) matchvec->index;
1815 vector_only_wrapper_free (matchvec);
1816 *status = CMD_COMPLETE_FULL_MATCH;
1817 return match_str;
1818 }
1819 /* Make it sure last element is NULL. */
1820 vector_set (matchvec, NULL);
1821
1822 /* Check LCD of matched strings. */
1823 if (vector_slot (vline, index) != NULL)
1824 {
1825 lcd = cmd_lcd ((char **) matchvec->index);
1826
1827 if (lcd)
1828 {
1829 int len = strlen (vector_slot (vline, index));
paul909a2152005-03-14 17:41:45 +00001830
paul718e3742002-12-13 20:15:29 +00001831 if (len < lcd)
1832 {
1833 char *lcdstr;
paul909a2152005-03-14 17:41:45 +00001834
paul05865c92005-10-26 05:49:54 +00001835 lcdstr = XMALLOC (MTYPE_STRVEC, lcd + 1);
paul718e3742002-12-13 20:15:29 +00001836 memcpy (lcdstr, matchvec->index[0], lcd);
1837 lcdstr[lcd] = '\0';
1838
1839 /* match_str = (char **) &lcdstr; */
1840
1841 /* Free matchvec. */
paul55468c82005-03-14 20:19:01 +00001842 for (i = 0; i < vector_active (matchvec); i++)
paul718e3742002-12-13 20:15:29 +00001843 {
1844 if (vector_slot (matchvec, i))
paul05865c92005-10-26 05:49:54 +00001845 XFREE (MTYPE_STRVEC, vector_slot (matchvec, i));
paul718e3742002-12-13 20:15:29 +00001846 }
1847 vector_free (matchvec);
1848
paul909a2152005-03-14 17:41:45 +00001849 /* Make new matchvec. */
paul718e3742002-12-13 20:15:29 +00001850 matchvec = vector_init (INIT_MATCHVEC_SIZE);
1851 vector_set (matchvec, lcdstr);
1852 match_str = (char **) matchvec->index;
1853 vector_only_wrapper_free (matchvec);
1854
1855 *status = CMD_COMPLETE_MATCH;
1856 return match_str;
1857 }
1858 }
1859 }
1860
1861 match_str = (char **) matchvec->index;
1862 vector_only_wrapper_free (matchvec);
1863 *status = CMD_COMPLETE_LIST_MATCH;
1864 return match_str;
1865}
1866
paulb92938a2002-12-13 21:20:42 +00001867char **
paul9ab68122003-01-18 01:16:20 +00001868cmd_complete_command (vector vline, struct vty *vty, int *status)
paulb92938a2002-12-13 21:20:42 +00001869{
1870 char **ret;
1871
1872 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
1873 {
1874 enum node_type onode;
1875 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00001876 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00001877
1878 onode = vty->node;
1879 vty->node = ENABLE_NODE;
1880 /* We can try it on enable node, cos' the vty is authenticated */
1881
1882 shifted_vline = vector_init (vector_count(vline));
1883 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00001884 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00001885 {
1886 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
1887 }
1888
1889 ret = cmd_complete_command_real (shifted_vline, vty, status);
1890
1891 vector_free(shifted_vline);
1892 vty->node = onode;
1893 return ret;
1894 }
1895
1896
1897 return cmd_complete_command_real (vline, vty, status);
1898}
1899
1900/* return parent node */
1901/* MUST eventually converge on CONFIG_NODE */
hasso13bfca72005-01-23 21:42:25 +00001902enum node_type
ajs274a4a42004-12-07 15:39:31 +00001903node_parent ( enum node_type node )
paulb92938a2002-12-13 21:20:42 +00001904{
1905 enum node_type ret;
1906
paul9ab68122003-01-18 01:16:20 +00001907 assert (node > CONFIG_NODE);
1908
1909 switch (node)
1910 {
1911 case BGP_VPNV4_NODE:
1912 case BGP_IPV4_NODE:
1913 case BGP_IPV4M_NODE:
1914 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00001915 case BGP_IPV6M_NODE:
paul9ab68122003-01-18 01:16:20 +00001916 ret = BGP_NODE;
1917 break;
1918 case KEYCHAIN_KEY_NODE:
1919 ret = KEYCHAIN_NODE;
1920 break;
1921 default:
1922 ret = CONFIG_NODE;
paulb92938a2002-12-13 21:20:42 +00001923 }
1924
1925 return ret;
1926}
1927
paul718e3742002-12-13 20:15:29 +00001928/* Execute command by argument vline vector. */
ajs274a4a42004-12-07 15:39:31 +00001929static int
paulb8961472005-03-14 17:35:52 +00001930cmd_execute_command_real (vector vline, struct vty *vty,
1931 struct cmd_element **cmd)
paul718e3742002-12-13 20:15:29 +00001932{
hasso8c328f12004-10-05 21:01:23 +00001933 unsigned int i;
1934 unsigned int index;
paul718e3742002-12-13 20:15:29 +00001935 vector cmd_vector;
1936 struct cmd_element *cmd_element;
1937 struct cmd_element *matched_element;
1938 unsigned int matched_count, incomplete_count;
1939 int argc;
paul9035efa2004-10-10 11:56:56 +00001940 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00001941 enum match_type match = 0;
1942 int varflag;
1943 char *command;
1944
1945 /* Make copy of command elements. */
1946 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
1947
paul55468c82005-03-14 20:19:01 +00001948 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00001949 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00001950 {
1951 int ret;
paul718e3742002-12-13 20:15:29 +00001952
paul909a2152005-03-14 17:41:45 +00001953 match = cmd_filter_by_completion (command, cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00001954
paul909a2152005-03-14 17:41:45 +00001955 if (match == vararg_match)
1956 break;
1957
1958 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
paul718e3742002-12-13 20:15:29 +00001959
paul909a2152005-03-14 17:41:45 +00001960 if (ret == 1)
1961 {
1962 vector_free (cmd_vector);
1963 return CMD_ERR_AMBIGUOUS;
1964 }
1965 else if (ret == 2)
1966 {
1967 vector_free (cmd_vector);
1968 return CMD_ERR_NO_MATCH;
1969 }
1970 }
paul718e3742002-12-13 20:15:29 +00001971
1972 /* Check matched count. */
1973 matched_element = NULL;
1974 matched_count = 0;
1975 incomplete_count = 0;
1976
paul55468c82005-03-14 20:19:01 +00001977 for (i = 0; i < vector_active (cmd_vector); i++)
paulb8961472005-03-14 17:35:52 +00001978 if ((cmd_element = vector_slot (cmd_vector, i)))
paul718e3742002-12-13 20:15:29 +00001979 {
paul718e3742002-12-13 20:15:29 +00001980 if (match == vararg_match || index >= cmd_element->cmdsize)
1981 {
1982 matched_element = cmd_element;
1983#if 0
1984 printf ("DEBUG: %s\n", cmd_element->string);
1985#endif
1986 matched_count++;
1987 }
1988 else
1989 {
1990 incomplete_count++;
1991 }
1992 }
paul909a2152005-03-14 17:41:45 +00001993
paul718e3742002-12-13 20:15:29 +00001994 /* Finish of using cmd_vector. */
1995 vector_free (cmd_vector);
1996
paul909a2152005-03-14 17:41:45 +00001997 /* To execute command, matched_count must be 1. */
1998 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00001999 {
2000 if (incomplete_count)
2001 return CMD_ERR_INCOMPLETE;
2002 else
2003 return CMD_ERR_NO_MATCH;
2004 }
2005
paul909a2152005-03-14 17:41:45 +00002006 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002007 return CMD_ERR_AMBIGUOUS;
2008
2009 /* Argument treatment */
2010 varflag = 0;
2011 argc = 0;
2012
paul55468c82005-03-14 20:19:01 +00002013 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002014 {
2015 if (varflag)
2016 argv[argc++] = vector_slot (vline, i);
2017 else
paul909a2152005-03-14 17:41:45 +00002018 {
paul718e3742002-12-13 20:15:29 +00002019 vector descvec = vector_slot (matched_element->strvec, i);
2020
paul55468c82005-03-14 20:19:01 +00002021 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002022 {
2023 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002024
hasso8c328f12004-10-05 21:01:23 +00002025 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002026 varflag = 1;
2027
hasso8c328f12004-10-05 21:01:23 +00002028 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002029 argv[argc++] = vector_slot (vline, i);
2030 }
2031 else
2032 argv[argc++] = vector_slot (vline, i);
2033 }
2034
2035 if (argc >= CMD_ARGC_MAX)
2036 return CMD_ERR_EXEED_ARGC_MAX;
2037 }
2038
2039 /* For vtysh execution. */
2040 if (cmd)
2041 *cmd = matched_element;
2042
2043 if (matched_element->daemon)
2044 return CMD_SUCCESS_DAEMON;
2045
2046 /* Execute matched command. */
2047 return (*matched_element->func) (matched_element, vty, argc, argv);
2048}
2049
paulb92938a2002-12-13 21:20:42 +00002050int
hasso87d683b2005-01-16 23:31:54 +00002051cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd,
2052 int vtysh) {
paul9ab68122003-01-18 01:16:20 +00002053 int ret, saved_ret, tried = 0;
2054 enum node_type onode, try_node;
2055
2056 onode = try_node = vty->node;
paulb92938a2002-12-13 21:20:42 +00002057
2058 if ( cmd_try_do_shortcut(vty->node, vector_slot(vline, 0) ) )
2059 {
2060 vector shifted_vline;
hasso8c328f12004-10-05 21:01:23 +00002061 unsigned int index;
paulb92938a2002-12-13 21:20:42 +00002062
2063 vty->node = ENABLE_NODE;
2064 /* We can try it on enable node, cos' the vty is authenticated */
2065
2066 shifted_vline = vector_init (vector_count(vline));
2067 /* use memcpy? */
paul55468c82005-03-14 20:19:01 +00002068 for (index = 1; index < vector_active (vline); index++)
paulb92938a2002-12-13 21:20:42 +00002069 {
2070 vector_set_index (shifted_vline, index-1, vector_lookup(vline, index));
2071 }
2072
2073 ret = cmd_execute_command_real (shifted_vline, vty, cmd);
2074
2075 vector_free(shifted_vline);
2076 vty->node = onode;
2077 return ret;
2078 }
2079
2080
paul9ab68122003-01-18 01:16:20 +00002081 saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);
paulb92938a2002-12-13 21:20:42 +00002082
hasso87d683b2005-01-16 23:31:54 +00002083 if (vtysh)
2084 return saved_ret;
2085
paulb92938a2002-12-13 21:20:42 +00002086 /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
paul9ab68122003-01-18 01:16:20 +00002087 while ( ret != CMD_SUCCESS && ret != CMD_WARNING
paulb92938a2002-12-13 21:20:42 +00002088 && vty->node > CONFIG_NODE )
2089 {
paul9ab68122003-01-18 01:16:20 +00002090 try_node = node_parent(try_node);
2091 vty->node = try_node;
paulb92938a2002-12-13 21:20:42 +00002092 ret = cmd_execute_command_real (vline, vty, cmd);
paul9ab68122003-01-18 01:16:20 +00002093 tried = 1;
2094 if (ret == CMD_SUCCESS || ret == CMD_WARNING)
paulb92938a2002-12-13 21:20:42 +00002095 {
paul9ab68122003-01-18 01:16:20 +00002096 /* succesfull command, leave the node as is */
paulb92938a2002-12-13 21:20:42 +00002097 return ret;
2098 }
paulb92938a2002-12-13 21:20:42 +00002099 }
paul9ab68122003-01-18 01:16:20 +00002100 /* no command succeeded, reset the vty to the original node and
2101 return the error for this node */
2102 if ( tried )
2103 vty->node = onode;
2104 return saved_ret;
pauleda031f2003-01-18 00:39:19 +00002105}
2106
paul718e3742002-12-13 20:15:29 +00002107/* Execute command by argument readline. */
2108int
paul909a2152005-03-14 17:41:45 +00002109cmd_execute_command_strict (vector vline, struct vty *vty,
paul718e3742002-12-13 20:15:29 +00002110 struct cmd_element **cmd)
2111{
hasso8c328f12004-10-05 21:01:23 +00002112 unsigned int i;
2113 unsigned int index;
paul718e3742002-12-13 20:15:29 +00002114 vector cmd_vector;
2115 struct cmd_element *cmd_element;
2116 struct cmd_element *matched_element;
2117 unsigned int matched_count, incomplete_count;
2118 int argc;
paul9035efa2004-10-10 11:56:56 +00002119 const char *argv[CMD_ARGC_MAX];
paul718e3742002-12-13 20:15:29 +00002120 int varflag;
2121 enum match_type match = 0;
2122 char *command;
2123
2124 /* Make copy of command element */
2125 cmd_vector = vector_copy (cmd_node_vector (cmdvec, vty->node));
2126
paul55468c82005-03-14 20:19:01 +00002127 for (index = 0; index < vector_active (vline); index++)
paulb8961472005-03-14 17:35:52 +00002128 if ((command = vector_slot (vline, index)))
paul909a2152005-03-14 17:41:45 +00002129 {
2130 int ret;
2131
2132 match = cmd_filter_by_string (vector_slot (vline, index),
2133 cmd_vector, index);
paul718e3742002-12-13 20:15:29 +00002134
paul909a2152005-03-14 17:41:45 +00002135 /* If command meets '.VARARG' then finish matching. */
2136 if (match == vararg_match)
2137 break;
2138
2139 ret = is_cmd_ambiguous (command, cmd_vector, index, match);
2140 if (ret == 1)
2141 {
2142 vector_free (cmd_vector);
2143 return CMD_ERR_AMBIGUOUS;
2144 }
2145 if (ret == 2)
2146 {
2147 vector_free (cmd_vector);
2148 return CMD_ERR_NO_MATCH;
2149 }
2150 }
paul718e3742002-12-13 20:15:29 +00002151
2152 /* Check matched count. */
2153 matched_element = NULL;
2154 matched_count = 0;
2155 incomplete_count = 0;
paul55468c82005-03-14 20:19:01 +00002156 for (i = 0; i < vector_active (cmd_vector); i++)
paul909a2152005-03-14 17:41:45 +00002157 if (vector_slot (cmd_vector, i) != NULL)
paul718e3742002-12-13 20:15:29 +00002158 {
paul909a2152005-03-14 17:41:45 +00002159 cmd_element = vector_slot (cmd_vector, i);
paul718e3742002-12-13 20:15:29 +00002160
2161 if (match == vararg_match || index >= cmd_element->cmdsize)
2162 {
2163 matched_element = cmd_element;
2164 matched_count++;
2165 }
2166 else
2167 incomplete_count++;
2168 }
paul909a2152005-03-14 17:41:45 +00002169
paul718e3742002-12-13 20:15:29 +00002170 /* Finish of using cmd_vector. */
2171 vector_free (cmd_vector);
2172
paul909a2152005-03-14 17:41:45 +00002173 /* To execute command, matched_count must be 1. */
2174 if (matched_count == 0)
paul718e3742002-12-13 20:15:29 +00002175 {
2176 if (incomplete_count)
2177 return CMD_ERR_INCOMPLETE;
2178 else
2179 return CMD_ERR_NO_MATCH;
2180 }
2181
paul909a2152005-03-14 17:41:45 +00002182 if (matched_count > 1)
paul718e3742002-12-13 20:15:29 +00002183 return CMD_ERR_AMBIGUOUS;
2184
2185 /* Argument treatment */
2186 varflag = 0;
2187 argc = 0;
2188
paul55468c82005-03-14 20:19:01 +00002189 for (i = 0; i < vector_active (vline); i++)
paul718e3742002-12-13 20:15:29 +00002190 {
2191 if (varflag)
2192 argv[argc++] = vector_slot (vline, i);
2193 else
paul909a2152005-03-14 17:41:45 +00002194 {
paul718e3742002-12-13 20:15:29 +00002195 vector descvec = vector_slot (matched_element->strvec, i);
2196
paul55468c82005-03-14 20:19:01 +00002197 if (vector_active (descvec) == 1)
paul718e3742002-12-13 20:15:29 +00002198 {
2199 struct desc *desc = vector_slot (descvec, 0);
paul718e3742002-12-13 20:15:29 +00002200
hasso8c328f12004-10-05 21:01:23 +00002201 if (CMD_VARARG (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002202 varflag = 1;
paul909a2152005-03-14 17:41:45 +00002203
hasso8c328f12004-10-05 21:01:23 +00002204 if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))
paul718e3742002-12-13 20:15:29 +00002205 argv[argc++] = vector_slot (vline, i);
2206 }
2207 else
2208 argv[argc++] = vector_slot (vline, i);
2209 }
2210
2211 if (argc >= CMD_ARGC_MAX)
2212 return CMD_ERR_EXEED_ARGC_MAX;
2213 }
2214
2215 /* For vtysh execution. */
2216 if (cmd)
2217 *cmd = matched_element;
2218
2219 if (matched_element->daemon)
2220 return CMD_SUCCESS_DAEMON;
2221
2222 /* Now execute matched command */
2223 return (*matched_element->func) (matched_element, vty, argc, argv);
2224}
2225
2226/* Configration make from file. */
2227int
2228config_from_file (struct vty *vty, FILE *fp)
2229{
2230 int ret;
2231 vector vline;
2232
2233 while (fgets (vty->buf, VTY_BUFSIZ, fp))
2234 {
2235 vline = cmd_make_strvec (vty->buf);
2236
2237 /* In case of comment line */
2238 if (vline == NULL)
2239 continue;
2240 /* Execute configuration command : this is strict match */
2241 ret = cmd_execute_command_strict (vline, vty, NULL);
2242
2243 /* Try again with setting node to CONFIG_NODE */
paulb92938a2002-12-13 21:20:42 +00002244 while (ret != CMD_SUCCESS && ret != CMD_WARNING
hassoddd85ed2004-10-13 08:18:07 +00002245 && ret != CMD_ERR_NOTHING_TODO && vty->node != CONFIG_NODE)
2246 {
paulb92938a2002-12-13 21:20:42 +00002247 vty->node = node_parent(vty->node);
hassoddd85ed2004-10-13 08:18:07 +00002248 ret = cmd_execute_command_strict (vline, vty, NULL);
2249 }
paul9ab68122003-01-18 01:16:20 +00002250
paul718e3742002-12-13 20:15:29 +00002251 cmd_free_strvec (vline);
2252
hassoddd85ed2004-10-13 08:18:07 +00002253 if (ret != CMD_SUCCESS && ret != CMD_WARNING
2254 && ret != CMD_ERR_NOTHING_TODO)
paul718e3742002-12-13 20:15:29 +00002255 return ret;
2256 }
2257 return CMD_SUCCESS;
2258}
2259
2260/* Configration from terminal */
2261DEFUN (config_terminal,
2262 config_terminal_cmd,
2263 "configure terminal",
2264 "Configuration from vty interface\n"
2265 "Configuration terminal\n")
2266{
2267 if (vty_config_lock (vty))
2268 vty->node = CONFIG_NODE;
2269 else
2270 {
2271 vty_out (vty, "VTY configuration is locked by other VTY%s", VTY_NEWLINE);
2272 return CMD_WARNING;
2273 }
2274 return CMD_SUCCESS;
2275}
2276
2277/* Enable command */
2278DEFUN (enable,
2279 config_enable_cmd,
2280 "enable",
2281 "Turn on privileged mode command\n")
2282{
2283 /* If enable password is NULL, change to ENABLE_NODE */
2284 if ((host.enable == NULL && host.enable_encrypt == NULL) ||
2285 vty->type == VTY_SHELL_SERV)
2286 vty->node = ENABLE_NODE;
2287 else
2288 vty->node = AUTH_ENABLE_NODE;
2289
2290 return CMD_SUCCESS;
2291}
2292
2293/* Disable command */
2294DEFUN (disable,
2295 config_disable_cmd,
2296 "disable",
2297 "Turn off privileged mode command\n")
2298{
2299 if (vty->node == ENABLE_NODE)
2300 vty->node = VIEW_NODE;
2301 return CMD_SUCCESS;
2302}
2303
2304/* Down vty node level. */
2305DEFUN (config_exit,
2306 config_exit_cmd,
2307 "exit",
2308 "Exit current mode and down to previous mode\n")
2309{
2310 switch (vty->node)
2311 {
2312 case VIEW_NODE:
2313 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002314 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002315 if (vty_shell (vty))
2316 exit (0);
2317 else
2318 vty->status = VTY_CLOSE;
2319 break;
2320 case CONFIG_NODE:
2321 vty->node = ENABLE_NODE;
2322 vty_config_unlock (vty);
2323 break;
2324 case INTERFACE_NODE:
2325 case ZEBRA_NODE:
2326 case BGP_NODE:
2327 case RIP_NODE:
2328 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002329 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002330 case OSPF_NODE:
2331 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002332 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002333 case KEYCHAIN_NODE:
2334 case MASC_NODE:
2335 case RMAP_NODE:
2336 case VTY_NODE:
2337 vty->node = CONFIG_NODE;
2338 break;
2339 case BGP_VPNV4_NODE:
2340 case BGP_IPV4_NODE:
2341 case BGP_IPV4M_NODE:
2342 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002343 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002344 vty->node = BGP_NODE;
2345 break;
2346 case KEYCHAIN_KEY_NODE:
2347 vty->node = KEYCHAIN_NODE;
2348 break;
2349 default:
2350 break;
2351 }
2352 return CMD_SUCCESS;
2353}
2354
2355/* quit is alias of exit. */
2356ALIAS (config_exit,
2357 config_quit_cmd,
2358 "quit",
2359 "Exit current mode and down to previous mode\n")
2360
2361/* End of configuration. */
2362DEFUN (config_end,
2363 config_end_cmd,
2364 "end",
2365 "End current mode and change to enable mode.")
2366{
2367 switch (vty->node)
2368 {
2369 case VIEW_NODE:
2370 case ENABLE_NODE:
Paul Jakma62687ff2008-08-23 14:27:06 +01002371 case RESTRICTED_NODE:
paul718e3742002-12-13 20:15:29 +00002372 /* Nothing to do. */
2373 break;
2374 case CONFIG_NODE:
2375 case INTERFACE_NODE:
2376 case ZEBRA_NODE:
2377 case RIP_NODE:
2378 case RIPNG_NODE:
Paul Jakma57345092011-12-25 17:52:09 +01002379 case BABEL_NODE:
paul718e3742002-12-13 20:15:29 +00002380 case BGP_NODE:
2381 case BGP_VPNV4_NODE:
2382 case BGP_IPV4_NODE:
2383 case BGP_IPV4M_NODE:
2384 case BGP_IPV6_NODE:
paul1e836592005-08-22 22:39:56 +00002385 case BGP_IPV6M_NODE:
paul718e3742002-12-13 20:15:29 +00002386 case RMAP_NODE:
2387 case OSPF_NODE:
2388 case OSPF6_NODE:
jardin9e867fe2003-12-23 08:56:18 +00002389 case ISIS_NODE:
paul718e3742002-12-13 20:15:29 +00002390 case KEYCHAIN_NODE:
2391 case KEYCHAIN_KEY_NODE:
2392 case MASC_NODE:
2393 case VTY_NODE:
2394 vty_config_unlock (vty);
2395 vty->node = ENABLE_NODE;
2396 break;
2397 default:
2398 break;
2399 }
2400 return CMD_SUCCESS;
2401}
2402
2403/* Show version. */
2404DEFUN (show_version,
2405 show_version_cmd,
2406 "show version",
2407 SHOW_STR
2408 "Displays zebra version\n")
2409{
hasso12f6ea22005-03-07 08:35:39 +00002410 vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",
2411 VTY_NEWLINE);
hasso6590f2c2004-10-19 20:40:08 +00002412 vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +00002413
2414 return CMD_SUCCESS;
2415}
2416
2417/* Help display function for all node. */
2418DEFUN (config_help,
2419 config_help_cmd,
2420 "help",
2421 "Description of the interactive help system\n")
2422{
2423 vty_out (vty,
hasso6590f2c2004-10-19 20:40:08 +00002424 "Quagga VTY provides advanced help feature. When you need help,%s\
paul718e3742002-12-13 20:15:29 +00002425anytime at the command line please press '?'.%s\
2426%s\
2427If nothing matches, the help list will be empty and you must backup%s\
2428 until entering a '?' shows the available options.%s\
2429Two styles of help are provided:%s\
24301. Full help is available when you are ready to enter a%s\
2431command argument (e.g. 'show ?') and describes each possible%s\
2432argument.%s\
24332. Partial help is provided when an abbreviated argument is entered%s\
2434 and you want to know what arguments match the input%s\
2435 (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2436 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2437 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2438 return CMD_SUCCESS;
2439}
2440
2441/* Help display function for all node. */
2442DEFUN (config_list,
2443 config_list_cmd,
2444 "list",
2445 "Print command list\n")
2446{
hasso8c328f12004-10-05 21:01:23 +00002447 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002448 struct cmd_node *cnode = vector_slot (cmdvec, vty->node);
2449 struct cmd_element *cmd;
2450
paul55468c82005-03-14 20:19:01 +00002451 for (i = 0; i < vector_active (cnode->cmd_vector); i++)
paul4275b1d2005-03-09 13:42:23 +00002452 if ((cmd = vector_slot (cnode->cmd_vector, i)) != NULL
2453 && !(cmd->attr == CMD_ATTR_DEPRECATED
2454 || cmd->attr == CMD_ATTR_HIDDEN))
paul718e3742002-12-13 20:15:29 +00002455 vty_out (vty, " %s%s", cmd->string,
2456 VTY_NEWLINE);
2457 return CMD_SUCCESS;
2458}
2459
2460/* Write current configuration into file. */
2461DEFUN (config_write_file,
2462 config_write_file_cmd,
2463 "write file",
2464 "Write running configuration to memory, network, or terminal\n"
2465 "Write to configuration file\n")
2466{
hasso8c328f12004-10-05 21:01:23 +00002467 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002468 int fd;
2469 struct cmd_node *node;
2470 char *config_file;
2471 char *config_file_tmp = NULL;
2472 char *config_file_sav = NULL;
paul05865c92005-10-26 05:49:54 +00002473 int ret = CMD_WARNING;
paul718e3742002-12-13 20:15:29 +00002474 struct vty *file_vty;
2475
2476 /* Check and see if we are operating under vtysh configuration */
2477 if (host.config == NULL)
2478 {
2479 vty_out (vty, "Can't save to configuration file, using vtysh.%s",
2480 VTY_NEWLINE);
2481 return CMD_WARNING;
2482 }
2483
2484 /* Get filename. */
2485 config_file = host.config;
2486
paul05865c92005-10-26 05:49:54 +00002487 config_file_sav =
2488 XMALLOC (MTYPE_TMP, strlen (config_file) + strlen (CONF_BACKUP_EXT) + 1);
paul718e3742002-12-13 20:15:29 +00002489 strcpy (config_file_sav, config_file);
2490 strcat (config_file_sav, CONF_BACKUP_EXT);
2491
2492
paul05865c92005-10-26 05:49:54 +00002493 config_file_tmp = XMALLOC (MTYPE_TMP, strlen (config_file) + 8);
paul718e3742002-12-13 20:15:29 +00002494 sprintf (config_file_tmp, "%s.XXXXXX", config_file);
2495
2496 /* Open file to configuration write. */
2497 fd = mkstemp (config_file_tmp);
2498 if (fd < 0)
2499 {
2500 vty_out (vty, "Can't open configuration file %s.%s", config_file_tmp,
2501 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002502 goto finished;
paul718e3742002-12-13 20:15:29 +00002503 }
2504
2505 /* Make vty for configuration file. */
2506 file_vty = vty_new ();
2507 file_vty->fd = fd;
2508 file_vty->type = VTY_FILE;
2509
2510 /* Config file header print. */
2511 vty_out (file_vty, "!\n! Zebra configuration saved from vty\n! ");
2512 vty_time_print (file_vty, 1);
2513 vty_out (file_vty, "!\n");
2514
paul55468c82005-03-14 20:19:01 +00002515 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002516 if ((node = vector_slot (cmdvec, i)) && node->func)
2517 {
2518 if ((*node->func) (file_vty))
2519 vty_out (file_vty, "!\n");
2520 }
2521 vty_close (file_vty);
2522
2523 if (unlink (config_file_sav) != 0)
2524 if (errno != ENOENT)
2525 {
2526 vty_out (vty, "Can't unlink backup configuration file %s.%s", config_file_sav,
2527 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002528 goto finished;
paul718e3742002-12-13 20:15:29 +00002529 }
2530 if (link (config_file, config_file_sav) != 0)
2531 {
2532 vty_out (vty, "Can't backup old configuration file %s.%s", config_file_sav,
2533 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002534 goto finished;
paul718e3742002-12-13 20:15:29 +00002535 }
2536 sync ();
2537 if (unlink (config_file) != 0)
2538 {
2539 vty_out (vty, "Can't unlink configuration file %s.%s", config_file,
2540 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002541 goto finished;
paul718e3742002-12-13 20:15:29 +00002542 }
2543 if (link (config_file_tmp, config_file) != 0)
2544 {
2545 vty_out (vty, "Can't save configuration file %s.%s", config_file,
2546 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002547 goto finished;
paul718e3742002-12-13 20:15:29 +00002548 }
paul718e3742002-12-13 20:15:29 +00002549 sync ();
2550
gdtaa593d52003-12-22 20:15:53 +00002551 if (chmod (config_file, CONFIGFILE_MASK) != 0)
2552 {
2553 vty_out (vty, "Can't chmod configuration file %s: %s (%d).%s",
ajs6099b3b2004-11-20 02:06:59 +00002554 config_file, safe_strerror(errno), errno, VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002555 goto finished;
gdtaa593d52003-12-22 20:15:53 +00002556 }
2557
paul718e3742002-12-13 20:15:29 +00002558 vty_out (vty, "Configuration saved to %s%s", config_file,
2559 VTY_NEWLINE);
paul05865c92005-10-26 05:49:54 +00002560 ret = CMD_SUCCESS;
2561
2562finished:
2563 unlink (config_file_tmp);
2564 XFREE (MTYPE_TMP, config_file_tmp);
2565 XFREE (MTYPE_TMP, config_file_sav);
2566 return ret;
paul718e3742002-12-13 20:15:29 +00002567}
2568
2569ALIAS (config_write_file,
2570 config_write_cmd,
2571 "write",
2572 "Write running configuration to memory, network, or terminal\n")
2573
2574ALIAS (config_write_file,
2575 config_write_memory_cmd,
2576 "write memory",
2577 "Write running configuration to memory, network, or terminal\n"
2578 "Write configuration to the file (same as write file)\n")
2579
2580ALIAS (config_write_file,
2581 copy_runningconfig_startupconfig_cmd,
2582 "copy running-config startup-config",
2583 "Copy configuration\n"
2584 "Copy running config to... \n"
2585 "Copy running config to startup config (same as write file)\n")
2586
2587/* Write current configuration into the terminal. */
2588DEFUN (config_write_terminal,
2589 config_write_terminal_cmd,
2590 "write terminal",
2591 "Write running configuration to memory, network, or terminal\n"
2592 "Write to terminal\n")
2593{
hasso8c328f12004-10-05 21:01:23 +00002594 unsigned int i;
paul718e3742002-12-13 20:15:29 +00002595 struct cmd_node *node;
2596
2597 if (vty->type == VTY_SHELL_SERV)
2598 {
paul55468c82005-03-14 20:19:01 +00002599 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002600 if ((node = vector_slot (cmdvec, i)) && node->func && node->vtysh)
2601 {
2602 if ((*node->func) (vty))
2603 vty_out (vty, "!%s", VTY_NEWLINE);
2604 }
2605 }
2606 else
2607 {
2608 vty_out (vty, "%sCurrent configuration:%s", VTY_NEWLINE,
2609 VTY_NEWLINE);
2610 vty_out (vty, "!%s", VTY_NEWLINE);
2611
paul55468c82005-03-14 20:19:01 +00002612 for (i = 0; i < vector_active (cmdvec); i++)
paul718e3742002-12-13 20:15:29 +00002613 if ((node = vector_slot (cmdvec, i)) && node->func)
2614 {
2615 if ((*node->func) (vty))
2616 vty_out (vty, "!%s", VTY_NEWLINE);
2617 }
2618 vty_out (vty, "end%s",VTY_NEWLINE);
2619 }
2620 return CMD_SUCCESS;
2621}
2622
2623/* Write current configuration into the terminal. */
2624ALIAS (config_write_terminal,
2625 show_running_config_cmd,
2626 "show running-config",
2627 SHOW_STR
2628 "running configuration\n")
2629
2630/* Write startup configuration into the terminal. */
2631DEFUN (show_startup_config,
2632 show_startup_config_cmd,
2633 "show startup-config",
2634 SHOW_STR
2635 "Contentes of startup configuration\n")
2636{
2637 char buf[BUFSIZ];
2638 FILE *confp;
2639
2640 confp = fopen (host.config, "r");
2641 if (confp == NULL)
2642 {
2643 vty_out (vty, "Can't open configuration file [%s]%s",
2644 host.config, VTY_NEWLINE);
2645 return CMD_WARNING;
2646 }
2647
2648 while (fgets (buf, BUFSIZ, confp))
2649 {
2650 char *cp = buf;
2651
2652 while (*cp != '\r' && *cp != '\n' && *cp != '\0')
2653 cp++;
2654 *cp = '\0';
2655
2656 vty_out (vty, "%s%s", buf, VTY_NEWLINE);
2657 }
2658
2659 fclose (confp);
2660
2661 return CMD_SUCCESS;
2662}
2663
2664/* Hostname configuration */
2665DEFUN (config_hostname,
2666 hostname_cmd,
2667 "hostname WORD",
2668 "Set system's network name\n"
2669 "This system's network name\n")
2670{
2671 if (!isalpha((int) *argv[0]))
2672 {
2673 vty_out (vty, "Please specify string starting with alphabet%s", VTY_NEWLINE);
2674 return CMD_WARNING;
2675 }
2676
2677 if (host.name)
paul05865c92005-10-26 05:49:54 +00002678 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002679
paul05865c92005-10-26 05:49:54 +00002680 host.name = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002681 return CMD_SUCCESS;
2682}
2683
2684DEFUN (config_no_hostname,
2685 no_hostname_cmd,
2686 "no hostname [HOSTNAME]",
2687 NO_STR
2688 "Reset system's network name\n"
2689 "Host name of this router\n")
2690{
2691 if (host.name)
paul05865c92005-10-26 05:49:54 +00002692 XFREE (MTYPE_HOST, host.name);
paul718e3742002-12-13 20:15:29 +00002693 host.name = NULL;
2694 return CMD_SUCCESS;
2695}
2696
2697/* VTY interface password set. */
2698DEFUN (config_password, password_cmd,
2699 "password (8|) WORD",
2700 "Assign the terminal connection password\n"
2701 "Specifies a HIDDEN password will follow\n"
2702 "dummy string \n"
2703 "The HIDDEN line password string\n")
2704{
2705 /* Argument check. */
2706 if (argc == 0)
2707 {
2708 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2709 return CMD_WARNING;
2710 }
2711
2712 if (argc == 2)
2713 {
2714 if (*argv[0] == '8')
2715 {
2716 if (host.password)
paul05865c92005-10-26 05:49:54 +00002717 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002718 host.password = NULL;
2719 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002720 XFREE (MTYPE_HOST, host.password_encrypt);
2721 host.password_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002722 return CMD_SUCCESS;
2723 }
2724 else
2725 {
2726 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2727 return CMD_WARNING;
2728 }
2729 }
2730
2731 if (!isalnum ((int) *argv[0]))
2732 {
2733 vty_out (vty,
2734 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2735 return CMD_WARNING;
2736 }
2737
2738 if (host.password)
paul05865c92005-10-26 05:49:54 +00002739 XFREE (MTYPE_HOST, host.password);
paul718e3742002-12-13 20:15:29 +00002740 host.password = NULL;
2741
2742 if (host.encrypt)
2743 {
2744 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002745 XFREE (MTYPE_HOST, host.password_encrypt);
2746 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002747 }
2748 else
paul05865c92005-10-26 05:49:54 +00002749 host.password = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002750
2751 return CMD_SUCCESS;
2752}
2753
2754ALIAS (config_password, password_text_cmd,
2755 "password LINE",
2756 "Assign the terminal connection password\n"
2757 "The UNENCRYPTED (cleartext) line password\n")
2758
2759/* VTY enable password set. */
2760DEFUN (config_enable_password, enable_password_cmd,
2761 "enable password (8|) WORD",
2762 "Modify enable password parameters\n"
2763 "Assign the privileged level password\n"
2764 "Specifies a HIDDEN password will follow\n"
2765 "dummy string \n"
2766 "The HIDDEN 'enable' password string\n")
2767{
2768 /* Argument check. */
2769 if (argc == 0)
2770 {
2771 vty_out (vty, "Please specify password.%s", VTY_NEWLINE);
2772 return CMD_WARNING;
2773 }
2774
2775 /* Crypt type is specified. */
2776 if (argc == 2)
2777 {
2778 if (*argv[0] == '8')
2779 {
2780 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002781 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002782 host.enable = NULL;
2783
2784 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002785 XFREE (MTYPE_HOST, host.enable_encrypt);
2786 host.enable_encrypt = XSTRDUP (MTYPE_HOST, argv[1]);
paul718e3742002-12-13 20:15:29 +00002787
2788 return CMD_SUCCESS;
2789 }
2790 else
2791 {
2792 vty_out (vty, "Unknown encryption type.%s", VTY_NEWLINE);
2793 return CMD_WARNING;
2794 }
2795 }
2796
2797 if (!isalnum ((int) *argv[0]))
2798 {
2799 vty_out (vty,
2800 "Please specify string starting with alphanumeric%s", VTY_NEWLINE);
2801 return CMD_WARNING;
2802 }
2803
2804 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002805 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002806 host.enable = NULL;
2807
2808 /* Plain password input. */
2809 if (host.encrypt)
2810 {
2811 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002812 XFREE (MTYPE_HOST, host.enable_encrypt);
2813 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (argv[0]));
paul718e3742002-12-13 20:15:29 +00002814 }
2815 else
paul05865c92005-10-26 05:49:54 +00002816 host.enable = XSTRDUP (MTYPE_HOST, argv[0]);
paul718e3742002-12-13 20:15:29 +00002817
2818 return CMD_SUCCESS;
2819}
2820
2821ALIAS (config_enable_password,
2822 enable_password_text_cmd,
2823 "enable password LINE",
2824 "Modify enable password parameters\n"
2825 "Assign the privileged level password\n"
2826 "The UNENCRYPTED (cleartext) 'enable' password\n")
2827
2828/* VTY enable password delete. */
2829DEFUN (no_config_enable_password, no_enable_password_cmd,
2830 "no enable password",
2831 NO_STR
2832 "Modify enable password parameters\n"
2833 "Assign the privileged level password\n")
2834{
2835 if (host.enable)
paul05865c92005-10-26 05:49:54 +00002836 XFREE (MTYPE_HOST, host.enable);
paul718e3742002-12-13 20:15:29 +00002837 host.enable = NULL;
2838
2839 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002840 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002841 host.enable_encrypt = NULL;
2842
2843 return CMD_SUCCESS;
2844}
2845
2846DEFUN (service_password_encrypt,
2847 service_password_encrypt_cmd,
2848 "service password-encryption",
2849 "Set up miscellaneous service\n"
2850 "Enable encrypted passwords\n")
2851{
2852 if (host.encrypt)
2853 return CMD_SUCCESS;
2854
2855 host.encrypt = 1;
2856
2857 if (host.password)
2858 {
2859 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002860 XFREE (MTYPE_HOST, host.password_encrypt);
2861 host.password_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.password));
paul718e3742002-12-13 20:15:29 +00002862 }
2863 if (host.enable)
2864 {
2865 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002866 XFREE (MTYPE_HOST, host.enable_encrypt);
2867 host.enable_encrypt = XSTRDUP (MTYPE_HOST, zencrypt (host.enable));
paul718e3742002-12-13 20:15:29 +00002868 }
2869
2870 return CMD_SUCCESS;
2871}
2872
2873DEFUN (no_service_password_encrypt,
2874 no_service_password_encrypt_cmd,
2875 "no service password-encryption",
2876 NO_STR
2877 "Set up miscellaneous service\n"
2878 "Enable encrypted passwords\n")
2879{
2880 if (! host.encrypt)
2881 return CMD_SUCCESS;
2882
2883 host.encrypt = 0;
2884
2885 if (host.password_encrypt)
paul05865c92005-10-26 05:49:54 +00002886 XFREE (MTYPE_HOST, host.password_encrypt);
paul718e3742002-12-13 20:15:29 +00002887 host.password_encrypt = NULL;
2888
2889 if (host.enable_encrypt)
paul05865c92005-10-26 05:49:54 +00002890 XFREE (MTYPE_HOST, host.enable_encrypt);
paul718e3742002-12-13 20:15:29 +00002891 host.enable_encrypt = NULL;
2892
2893 return CMD_SUCCESS;
2894}
2895
2896DEFUN (config_terminal_length, config_terminal_length_cmd,
2897 "terminal length <0-512>",
2898 "Set terminal line parameters\n"
2899 "Set number of lines on a screen\n"
2900 "Number of lines on screen (0 for no pausing)\n")
2901{
2902 int lines;
2903 char *endptr = NULL;
2904
2905 lines = strtol (argv[0], &endptr, 10);
2906 if (lines < 0 || lines > 512 || *endptr != '\0')
2907 {
2908 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2909 return CMD_WARNING;
2910 }
2911 vty->lines = lines;
2912
2913 return CMD_SUCCESS;
2914}
2915
2916DEFUN (config_terminal_no_length, config_terminal_no_length_cmd,
2917 "terminal no length",
2918 "Set terminal line parameters\n"
2919 NO_STR
2920 "Set number of lines on a screen\n")
2921{
2922 vty->lines = -1;
2923 return CMD_SUCCESS;
2924}
2925
2926DEFUN (service_terminal_length, service_terminal_length_cmd,
2927 "service terminal-length <0-512>",
2928 "Set up miscellaneous service\n"
2929 "System wide terminal length configuration\n"
2930 "Number of lines of VTY (0 means no line control)\n")
2931{
2932 int lines;
2933 char *endptr = NULL;
2934
2935 lines = strtol (argv[0], &endptr, 10);
2936 if (lines < 0 || lines > 512 || *endptr != '\0')
2937 {
2938 vty_out (vty, "length is malformed%s", VTY_NEWLINE);
2939 return CMD_WARNING;
2940 }
2941 host.lines = lines;
2942
2943 return CMD_SUCCESS;
2944}
2945
2946DEFUN (no_service_terminal_length, no_service_terminal_length_cmd,
2947 "no service terminal-length [<0-512>]",
2948 NO_STR
2949 "Set up miscellaneous service\n"
2950 "System wide terminal length configuration\n"
2951 "Number of lines of VTY (0 means no line control)\n")
2952{
2953 host.lines = -1;
2954 return CMD_SUCCESS;
2955}
2956
ajs2885f722004-12-17 23:16:33 +00002957DEFUN_HIDDEN (do_echo,
2958 echo_cmd,
2959 "echo .MESSAGE",
2960 "Echo a message back to the vty\n"
2961 "The message to echo\n")
2962{
2963 char *message;
2964
ajsf6834d42005-01-28 20:28:35 +00002965 vty_out (vty, "%s%s", ((message = argv_concat(argv, argc, 0)) ? message : ""),
2966 VTY_NEWLINE);
2967 if (message)
2968 XFREE(MTYPE_TMP, message);
ajs2885f722004-12-17 23:16:33 +00002969 return CMD_SUCCESS;
2970}
2971
ajs274a4a42004-12-07 15:39:31 +00002972DEFUN (config_logmsg,
2973 config_logmsg_cmd,
2974 "logmsg "LOG_LEVELS" .MESSAGE",
2975 "Send a message to enabled logging destinations\n"
2976 LOG_LEVEL_DESC
2977 "The message to send\n")
2978{
2979 int level;
2980 char *message;
2981
2982 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
2983 return CMD_ERR_NO_MATCH;
2984
Christian Hammersfc951862011-03-23 13:07:55 +03002985 zlog(NULL, level, "%s", ((message = argv_concat(argv, argc, 1)) ? message : ""));
ajsf6834d42005-01-28 20:28:35 +00002986 if (message)
2987 XFREE(MTYPE_TMP, message);
ajs274a4a42004-12-07 15:39:31 +00002988 return CMD_SUCCESS;
2989}
2990
2991DEFUN (show_logging,
2992 show_logging_cmd,
2993 "show logging",
2994 SHOW_STR
2995 "Show current logging configuration\n")
2996{
2997 struct zlog *zl = zlog_default;
2998
2999 vty_out (vty, "Syslog logging: ");
3000 if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
3001 vty_out (vty, "disabled");
3002 else
3003 vty_out (vty, "level %s, facility %s, ident %s",
3004 zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
3005 facility_name(zl->facility), zl->ident);
3006 vty_out (vty, "%s", VTY_NEWLINE);
3007
3008 vty_out (vty, "Stdout logging: ");
3009 if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
3010 vty_out (vty, "disabled");
3011 else
3012 vty_out (vty, "level %s",
3013 zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
3014 vty_out (vty, "%s", VTY_NEWLINE);
3015
3016 vty_out (vty, "Monitor logging: ");
3017 if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
3018 vty_out (vty, "disabled");
3019 else
3020 vty_out (vty, "level %s",
3021 zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
3022 vty_out (vty, "%s", VTY_NEWLINE);
3023
3024 vty_out (vty, "File logging: ");
3025 if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) ||
3026 !zl->fp)
3027 vty_out (vty, "disabled");
3028 else
3029 vty_out (vty, "level %s, filename %s",
3030 zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
3031 zl->filename);
3032 vty_out (vty, "%s", VTY_NEWLINE);
3033
3034 vty_out (vty, "Protocol name: %s%s",
3035 zlog_proto_names[zl->protocol], VTY_NEWLINE);
3036 vty_out (vty, "Record priority: %s%s",
3037 (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003038 vty_out (vty, "Timestamp precision: %d%s",
3039 zl->timestamp_precision, VTY_NEWLINE);
ajs274a4a42004-12-07 15:39:31 +00003040
3041 return CMD_SUCCESS;
3042}
3043
paul718e3742002-12-13 20:15:29 +00003044DEFUN (config_log_stdout,
3045 config_log_stdout_cmd,
3046 "log stdout",
3047 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003048 "Set stdout logging level\n")
paul718e3742002-12-13 20:15:29 +00003049{
ajs274a4a42004-12-07 15:39:31 +00003050 zlog_set_level (NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
3051 return CMD_SUCCESS;
3052}
3053
3054DEFUN (config_log_stdout_level,
3055 config_log_stdout_level_cmd,
3056 "log stdout "LOG_LEVELS,
3057 "Logging control\n"
3058 "Set stdout logging level\n"
3059 LOG_LEVEL_DESC)
3060{
3061 int level;
3062
3063 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3064 return CMD_ERR_NO_MATCH;
3065 zlog_set_level (NULL, ZLOG_DEST_STDOUT, level);
paul718e3742002-12-13 20:15:29 +00003066 return CMD_SUCCESS;
3067}
3068
3069DEFUN (no_config_log_stdout,
3070 no_config_log_stdout_cmd,
ajs274a4a42004-12-07 15:39:31 +00003071 "no log stdout [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003072 NO_STR
3073 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003074 "Cancel logging to stdout\n"
3075 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003076{
ajs274a4a42004-12-07 15:39:31 +00003077 zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003078 return CMD_SUCCESS;
3079}
3080
ajs274a4a42004-12-07 15:39:31 +00003081DEFUN (config_log_monitor,
3082 config_log_monitor_cmd,
3083 "log monitor",
paul718e3742002-12-13 20:15:29 +00003084 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003085 "Set terminal line (monitor) logging level\n")
3086{
3087 zlog_set_level (NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
3088 return CMD_SUCCESS;
3089}
3090
3091DEFUN (config_log_monitor_level,
3092 config_log_monitor_level_cmd,
3093 "log monitor "LOG_LEVELS,
3094 "Logging control\n"
3095 "Set terminal line (monitor) logging level\n"
3096 LOG_LEVEL_DESC)
3097{
3098 int level;
3099
3100 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3101 return CMD_ERR_NO_MATCH;
3102 zlog_set_level (NULL, ZLOG_DEST_MONITOR, level);
3103 return CMD_SUCCESS;
3104}
3105
3106DEFUN (no_config_log_monitor,
3107 no_config_log_monitor_cmd,
3108 "no log monitor [LEVEL]",
3109 NO_STR
3110 "Logging control\n"
3111 "Disable terminal line (monitor) logging\n"
3112 "Logging level\n")
3113{
3114 zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
3115 return CMD_SUCCESS;
3116}
3117
3118static int
3119set_log_file(struct vty *vty, const char *fname, int loglevel)
paul718e3742002-12-13 20:15:29 +00003120{
3121 int ret;
paul9035efa2004-10-10 11:56:56 +00003122 char *p = NULL;
3123 const char *fullpath;
3124
paul718e3742002-12-13 20:15:29 +00003125 /* Path detection. */
ajs274a4a42004-12-07 15:39:31 +00003126 if (! IS_DIRECTORY_SEP (*fname))
paul718e3742002-12-13 20:15:29 +00003127 {
paul9035efa2004-10-10 11:56:56 +00003128 char cwd[MAXPATHLEN+1];
3129 cwd[MAXPATHLEN] = '\0';
3130
3131 if (getcwd (cwd, MAXPATHLEN) == NULL)
3132 {
3133 zlog_err ("config_log_file: Unable to alloc mem!");
3134 return CMD_WARNING;
3135 }
3136
ajs274a4a42004-12-07 15:39:31 +00003137 if ( (p = XMALLOC (MTYPE_TMP, strlen (cwd) + strlen (fname) + 2))
paul9035efa2004-10-10 11:56:56 +00003138 == NULL)
3139 {
3140 zlog_err ("config_log_file: Unable to alloc mem!");
3141 return CMD_WARNING;
3142 }
ajs274a4a42004-12-07 15:39:31 +00003143 sprintf (p, "%s/%s", cwd, fname);
paul9035efa2004-10-10 11:56:56 +00003144 fullpath = p;
paul718e3742002-12-13 20:15:29 +00003145 }
3146 else
ajs274a4a42004-12-07 15:39:31 +00003147 fullpath = fname;
paul718e3742002-12-13 20:15:29 +00003148
ajs274a4a42004-12-07 15:39:31 +00003149 ret = zlog_set_file (NULL, fullpath, loglevel);
paul718e3742002-12-13 20:15:29 +00003150
paul9035efa2004-10-10 11:56:56 +00003151 if (p)
3152 XFREE (MTYPE_TMP, p);
3153
paul718e3742002-12-13 20:15:29 +00003154 if (!ret)
3155 {
ajs274a4a42004-12-07 15:39:31 +00003156 vty_out (vty, "can't open logfile %s\n", fname);
paul718e3742002-12-13 20:15:29 +00003157 return CMD_WARNING;
3158 }
3159
3160 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003161 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003162
paul05865c92005-10-26 05:49:54 +00003163 host.logfile = XSTRDUP (MTYPE_HOST, fname);
paul718e3742002-12-13 20:15:29 +00003164
3165 return CMD_SUCCESS;
3166}
3167
ajs274a4a42004-12-07 15:39:31 +00003168DEFUN (config_log_file,
3169 config_log_file_cmd,
3170 "log file FILENAME",
3171 "Logging control\n"
3172 "Logging to file\n"
3173 "Logging filename\n")
3174{
3175 return set_log_file(vty, argv[0], zlog_default->default_lvl);
3176}
3177
3178DEFUN (config_log_file_level,
3179 config_log_file_level_cmd,
3180 "log file FILENAME "LOG_LEVELS,
3181 "Logging control\n"
3182 "Logging to file\n"
3183 "Logging filename\n"
3184 LOG_LEVEL_DESC)
3185{
3186 int level;
3187
3188 if ((level = level_match(argv[1])) == ZLOG_DISABLED)
3189 return CMD_ERR_NO_MATCH;
3190 return set_log_file(vty, argv[0], level);
3191}
3192
paul718e3742002-12-13 20:15:29 +00003193DEFUN (no_config_log_file,
3194 no_config_log_file_cmd,
3195 "no log file [FILENAME]",
3196 NO_STR
3197 "Logging control\n"
3198 "Cancel logging to file\n"
3199 "Logging file name\n")
3200{
3201 zlog_reset_file (NULL);
3202
3203 if (host.logfile)
paul05865c92005-10-26 05:49:54 +00003204 XFREE (MTYPE_HOST, host.logfile);
paul718e3742002-12-13 20:15:29 +00003205
3206 host.logfile = NULL;
3207
3208 return CMD_SUCCESS;
3209}
3210
ajs274a4a42004-12-07 15:39:31 +00003211ALIAS (no_config_log_file,
3212 no_config_log_file_level_cmd,
3213 "no log file FILENAME LEVEL",
3214 NO_STR
3215 "Logging control\n"
3216 "Cancel logging to file\n"
3217 "Logging file name\n"
3218 "Logging level\n")
3219
paul718e3742002-12-13 20:15:29 +00003220DEFUN (config_log_syslog,
3221 config_log_syslog_cmd,
3222 "log syslog",
3223 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003224 "Set syslog logging level\n")
paul718e3742002-12-13 20:15:29 +00003225{
ajs274a4a42004-12-07 15:39:31 +00003226 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003227 return CMD_SUCCESS;
3228}
3229
ajs274a4a42004-12-07 15:39:31 +00003230DEFUN (config_log_syslog_level,
3231 config_log_syslog_level_cmd,
3232 "log syslog "LOG_LEVELS,
paul12ab19f2003-07-26 06:14:55 +00003233 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003234 "Set syslog logging level\n"
3235 LOG_LEVEL_DESC)
paul12ab19f2003-07-26 06:14:55 +00003236{
ajs274a4a42004-12-07 15:39:31 +00003237 int level;
paul12ab19f2003-07-26 06:14:55 +00003238
ajs274a4a42004-12-07 15:39:31 +00003239 if ((level = level_match(argv[0])) == ZLOG_DISABLED)
3240 return CMD_ERR_NO_MATCH;
3241 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, level);
3242 return CMD_SUCCESS;
3243}
paul12ab19f2003-07-26 06:14:55 +00003244
ajs274a4a42004-12-07 15:39:31 +00003245DEFUN_DEPRECATED (config_log_syslog_facility,
3246 config_log_syslog_facility_cmd,
3247 "log syslog facility "LOG_FACILITIES,
3248 "Logging control\n"
3249 "Logging goes to syslog\n"
3250 "(Deprecated) Facility parameter for syslog messages\n"
3251 LOG_FACILITY_DESC)
3252{
3253 int facility;
paul12ab19f2003-07-26 06:14:55 +00003254
ajs274a4a42004-12-07 15:39:31 +00003255 if ((facility = facility_match(argv[0])) < 0)
3256 return CMD_ERR_NO_MATCH;
3257
3258 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
paul12ab19f2003-07-26 06:14:55 +00003259 zlog_default->facility = facility;
paul718e3742002-12-13 20:15:29 +00003260 return CMD_SUCCESS;
3261}
3262
3263DEFUN (no_config_log_syslog,
3264 no_config_log_syslog_cmd,
ajs274a4a42004-12-07 15:39:31 +00003265 "no log syslog [LEVEL]",
paul718e3742002-12-13 20:15:29 +00003266 NO_STR
3267 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003268 "Cancel logging to syslog\n"
3269 "Logging level\n")
paul718e3742002-12-13 20:15:29 +00003270{
ajs274a4a42004-12-07 15:39:31 +00003271 zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
paul718e3742002-12-13 20:15:29 +00003272 return CMD_SUCCESS;
3273}
3274
paul12ab19f2003-07-26 06:14:55 +00003275ALIAS (no_config_log_syslog,
3276 no_config_log_syslog_facility_cmd,
ajs274a4a42004-12-07 15:39:31 +00003277 "no log syslog facility "LOG_FACILITIES,
paul12ab19f2003-07-26 06:14:55 +00003278 NO_STR
3279 "Logging control\n"
3280 "Logging goes to syslog\n"
3281 "Facility parameter for syslog messages\n"
ajs274a4a42004-12-07 15:39:31 +00003282 LOG_FACILITY_DESC)
paul12ab19f2003-07-26 06:14:55 +00003283
ajs274a4a42004-12-07 15:39:31 +00003284DEFUN (config_log_facility,
3285 config_log_facility_cmd,
3286 "log facility "LOG_FACILITIES,
paul718e3742002-12-13 20:15:29 +00003287 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003288 "Facility parameter for syslog messages\n"
3289 LOG_FACILITY_DESC)
paul718e3742002-12-13 20:15:29 +00003290{
ajs274a4a42004-12-07 15:39:31 +00003291 int facility;
3292
3293 if ((facility = facility_match(argv[0])) < 0)
3294 return CMD_ERR_NO_MATCH;
3295 zlog_default->facility = facility;
3296 return CMD_SUCCESS;
paul718e3742002-12-13 20:15:29 +00003297}
3298
ajs274a4a42004-12-07 15:39:31 +00003299DEFUN (no_config_log_facility,
3300 no_config_log_facility_cmd,
3301 "no log facility [FACILITY]",
paul718e3742002-12-13 20:15:29 +00003302 NO_STR
3303 "Logging control\n"
ajs274a4a42004-12-07 15:39:31 +00003304 "Reset syslog facility to default (daemon)\n"
3305 "Syslog facility\n")
paul718e3742002-12-13 20:15:29 +00003306{
ajs274a4a42004-12-07 15:39:31 +00003307 zlog_default->facility = LOG_DAEMON;
3308 return CMD_SUCCESS;
3309}
3310
3311DEFUN_DEPRECATED (config_log_trap,
3312 config_log_trap_cmd,
3313 "log trap "LOG_LEVELS,
3314 "Logging control\n"
3315 "(Deprecated) Set logging level and default for all destinations\n"
3316 LOG_LEVEL_DESC)
3317{
3318 int new_level ;
3319 int i;
3320
3321 if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
3322 return CMD_ERR_NO_MATCH;
3323
3324 zlog_default->default_lvl = new_level;
3325 for (i = 0; i < ZLOG_NUM_DESTS; i++)
3326 if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
3327 zlog_default->maxlvl[i] = new_level;
3328 return CMD_SUCCESS;
3329}
3330
3331DEFUN_DEPRECATED (no_config_log_trap,
3332 no_config_log_trap_cmd,
3333 "no log trap [LEVEL]",
3334 NO_STR
3335 "Logging control\n"
3336 "Permit all logging information\n"
3337 "Logging level\n")
3338{
3339 zlog_default->default_lvl = LOG_DEBUG;
paul718e3742002-12-13 20:15:29 +00003340 return CMD_SUCCESS;
3341}
3342
3343DEFUN (config_log_record_priority,
3344 config_log_record_priority_cmd,
3345 "log record-priority",
3346 "Logging control\n"
3347 "Log the priority of the message within the message\n")
3348{
3349 zlog_default->record_priority = 1 ;
3350 return CMD_SUCCESS;
3351}
3352
3353DEFUN (no_config_log_record_priority,
3354 no_config_log_record_priority_cmd,
3355 "no log record-priority",
3356 NO_STR
3357 "Logging control\n"
3358 "Do not log the priority of the message within the message\n")
3359{
3360 zlog_default->record_priority = 0 ;
3361 return CMD_SUCCESS;
3362}
3363
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003364DEFUN (config_log_timestamp_precision,
3365 config_log_timestamp_precision_cmd,
3366 "log timestamp precision <0-6>",
3367 "Logging control\n"
3368 "Timestamp configuration\n"
3369 "Set the timestamp precision\n"
3370 "Number of subsecond digits\n")
3371{
3372 if (argc != 1)
3373 {
3374 vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE);
3375 return CMD_WARNING;
3376 }
3377
3378 VTY_GET_INTEGER_RANGE("Timestamp Precision",
3379 zlog_default->timestamp_precision, argv[0], 0, 6);
3380 return CMD_SUCCESS;
3381}
3382
3383DEFUN (no_config_log_timestamp_precision,
3384 no_config_log_timestamp_precision_cmd,
3385 "no log timestamp precision",
3386 NO_STR
3387 "Logging control\n"
3388 "Timestamp configuration\n"
3389 "Reset the timestamp precision to the default value of 0\n")
3390{
3391 zlog_default->timestamp_precision = 0 ;
3392 return CMD_SUCCESS;
3393}
3394
paul3b0c5d92005-03-08 10:43:43 +00003395DEFUN (banner_motd_file,
3396 banner_motd_file_cmd,
3397 "banner motd file [FILE]",
3398 "Set banner\n"
3399 "Banner for motd\n"
3400 "Banner from a file\n"
3401 "Filename\n")
3402{
paulb45da6f2005-03-08 15:16:57 +00003403 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003404 XFREE (MTYPE_HOST, host.motdfile);
3405 host.motdfile = XSTRDUP (MTYPE_HOST, argv[0]);
paulb45da6f2005-03-08 15:16:57 +00003406
paul3b0c5d92005-03-08 10:43:43 +00003407 return CMD_SUCCESS;
3408}
paul718e3742002-12-13 20:15:29 +00003409
3410DEFUN (banner_motd_default,
3411 banner_motd_default_cmd,
3412 "banner motd default",
3413 "Set banner string\n"
3414 "Strings for motd\n"
3415 "Default string\n")
3416{
3417 host.motd = default_motd;
3418 return CMD_SUCCESS;
3419}
3420
3421DEFUN (no_banner_motd,
3422 no_banner_motd_cmd,
3423 "no banner motd",
3424 NO_STR
3425 "Set banner string\n"
3426 "Strings for motd\n")
3427{
3428 host.motd = NULL;
paul22085182005-03-08 16:00:12 +00003429 if (host.motdfile)
paul05865c92005-10-26 05:49:54 +00003430 XFREE (MTYPE_HOST, host.motdfile);
paul3b0c5d92005-03-08 10:43:43 +00003431 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003432 return CMD_SUCCESS;
3433}
3434
3435/* Set config filename. Called from vty.c */
3436void
3437host_config_set (char *filename)
3438{
Chris Caputo228da422009-07-18 05:44:03 +00003439 if (host.config)
3440 XFREE (MTYPE_HOST, host.config);
paul05865c92005-10-26 05:49:54 +00003441 host.config = XSTRDUP (MTYPE_HOST, filename);
paul718e3742002-12-13 20:15:29 +00003442}
3443
3444void
3445install_default (enum node_type node)
3446{
3447 install_element (node, &config_exit_cmd);
3448 install_element (node, &config_quit_cmd);
3449 install_element (node, &config_end_cmd);
3450 install_element (node, &config_help_cmd);
3451 install_element (node, &config_list_cmd);
3452
3453 install_element (node, &config_write_terminal_cmd);
3454 install_element (node, &config_write_file_cmd);
3455 install_element (node, &config_write_memory_cmd);
3456 install_element (node, &config_write_cmd);
3457 install_element (node, &show_running_config_cmd);
3458}
3459
3460/* Initialize command interface. Install basic nodes and commands. */
3461void
3462cmd_init (int terminal)
3463{
Chris Caputo228da422009-07-18 05:44:03 +00003464 command_cr = XSTRDUP(MTYPE_STRVEC, "<cr>");
3465 desc_cr.cmd = command_cr;
3466 desc_cr.str = XSTRDUP(MTYPE_STRVEC, "");
3467
paul718e3742002-12-13 20:15:29 +00003468 /* Allocate initial top vector of commands. */
3469 cmdvec = vector_init (VECTOR_MIN_SIZE);
3470
3471 /* Default host value settings. */
3472 host.name = NULL;
3473 host.password = NULL;
3474 host.enable = NULL;
3475 host.logfile = NULL;
3476 host.config = NULL;
3477 host.lines = -1;
3478 host.motd = default_motd;
paul3b0c5d92005-03-08 10:43:43 +00003479 host.motdfile = NULL;
paul718e3742002-12-13 20:15:29 +00003480
3481 /* Install top nodes. */
3482 install_node (&view_node, NULL);
3483 install_node (&enable_node, NULL);
3484 install_node (&auth_node, NULL);
3485 install_node (&auth_enable_node, NULL);
Paul Jakma62687ff2008-08-23 14:27:06 +01003486 install_node (&restricted_node, NULL);
paul718e3742002-12-13 20:15:29 +00003487 install_node (&config_node, config_write_host);
3488
3489 /* Each node's basic commands. */
3490 install_element (VIEW_NODE, &show_version_cmd);
3491 if (terminal)
3492 {
3493 install_element (VIEW_NODE, &config_list_cmd);
3494 install_element (VIEW_NODE, &config_exit_cmd);
3495 install_element (VIEW_NODE, &config_quit_cmd);
3496 install_element (VIEW_NODE, &config_help_cmd);
3497 install_element (VIEW_NODE, &config_enable_cmd);
3498 install_element (VIEW_NODE, &config_terminal_length_cmd);
3499 install_element (VIEW_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003500 install_element (VIEW_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003501 install_element (VIEW_NODE, &echo_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003502
3503 install_element (RESTRICTED_NODE, &config_list_cmd);
3504 install_element (RESTRICTED_NODE, &config_exit_cmd);
3505 install_element (RESTRICTED_NODE, &config_quit_cmd);
3506 install_element (RESTRICTED_NODE, &config_help_cmd);
3507 install_element (RESTRICTED_NODE, &config_enable_cmd);
3508 install_element (RESTRICTED_NODE, &config_terminal_length_cmd);
3509 install_element (RESTRICTED_NODE, &config_terminal_no_length_cmd);
3510 install_element (RESTRICTED_NODE, &echo_cmd);
paul718e3742002-12-13 20:15:29 +00003511 }
3512
3513 if (terminal)
3514 {
3515 install_default (ENABLE_NODE);
3516 install_element (ENABLE_NODE, &config_disable_cmd);
3517 install_element (ENABLE_NODE, &config_terminal_cmd);
3518 install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
3519 }
3520 install_element (ENABLE_NODE, &show_startup_config_cmd);
3521 install_element (ENABLE_NODE, &show_version_cmd);
paul718e3742002-12-13 20:15:29 +00003522
3523 if (terminal)
paul718e3742002-12-13 20:15:29 +00003524 {
hassoe7168df2004-10-03 20:11:32 +00003525 install_element (ENABLE_NODE, &config_terminal_length_cmd);
3526 install_element (ENABLE_NODE, &config_terminal_no_length_cmd);
ajs274a4a42004-12-07 15:39:31 +00003527 install_element (ENABLE_NODE, &show_logging_cmd);
ajs2885f722004-12-17 23:16:33 +00003528 install_element (ENABLE_NODE, &echo_cmd);
ajs274a4a42004-12-07 15:39:31 +00003529 install_element (ENABLE_NODE, &config_logmsg_cmd);
hassoe7168df2004-10-03 20:11:32 +00003530
3531 install_default (CONFIG_NODE);
hassoea8e9d92004-10-07 21:32:14 +00003532 }
3533
3534 install_element (CONFIG_NODE, &hostname_cmd);
3535 install_element (CONFIG_NODE, &no_hostname_cmd);
hassoe7168df2004-10-03 20:11:32 +00003536
hassoea8e9d92004-10-07 21:32:14 +00003537 if (terminal)
3538 {
hassoe7168df2004-10-03 20:11:32 +00003539 install_element (CONFIG_NODE, &password_cmd);
3540 install_element (CONFIG_NODE, &password_text_cmd);
3541 install_element (CONFIG_NODE, &enable_password_cmd);
3542 install_element (CONFIG_NODE, &enable_password_text_cmd);
3543 install_element (CONFIG_NODE, &no_enable_password_cmd);
3544
paul718e3742002-12-13 20:15:29 +00003545 install_element (CONFIG_NODE, &config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003546 install_element (CONFIG_NODE, &config_log_stdout_level_cmd);
paul718e3742002-12-13 20:15:29 +00003547 install_element (CONFIG_NODE, &no_config_log_stdout_cmd);
ajs274a4a42004-12-07 15:39:31 +00003548 install_element (CONFIG_NODE, &config_log_monitor_cmd);
3549 install_element (CONFIG_NODE, &config_log_monitor_level_cmd);
3550 install_element (CONFIG_NODE, &no_config_log_monitor_cmd);
paul718e3742002-12-13 20:15:29 +00003551 install_element (CONFIG_NODE, &config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003552 install_element (CONFIG_NODE, &config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003553 install_element (CONFIG_NODE, &no_config_log_file_cmd);
ajs274a4a42004-12-07 15:39:31 +00003554 install_element (CONFIG_NODE, &no_config_log_file_level_cmd);
paul718e3742002-12-13 20:15:29 +00003555 install_element (CONFIG_NODE, &config_log_syslog_cmd);
ajs274a4a42004-12-07 15:39:31 +00003556 install_element (CONFIG_NODE, &config_log_syslog_level_cmd);
paul12ab19f2003-07-26 06:14:55 +00003557 install_element (CONFIG_NODE, &config_log_syslog_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003558 install_element (CONFIG_NODE, &no_config_log_syslog_cmd);
paul12ab19f2003-07-26 06:14:55 +00003559 install_element (CONFIG_NODE, &no_config_log_syslog_facility_cmd);
ajs274a4a42004-12-07 15:39:31 +00003560 install_element (CONFIG_NODE, &config_log_facility_cmd);
3561 install_element (CONFIG_NODE, &no_config_log_facility_cmd);
paul718e3742002-12-13 20:15:29 +00003562 install_element (CONFIG_NODE, &config_log_trap_cmd);
3563 install_element (CONFIG_NODE, &no_config_log_trap_cmd);
3564 install_element (CONFIG_NODE, &config_log_record_priority_cmd);
3565 install_element (CONFIG_NODE, &no_config_log_record_priority_cmd);
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +00003566 install_element (CONFIG_NODE, &config_log_timestamp_precision_cmd);
3567 install_element (CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
paul718e3742002-12-13 20:15:29 +00003568 install_element (CONFIG_NODE, &service_password_encrypt_cmd);
3569 install_element (CONFIG_NODE, &no_service_password_encrypt_cmd);
3570 install_element (CONFIG_NODE, &banner_motd_default_cmd);
paul3b0c5d92005-03-08 10:43:43 +00003571 install_element (CONFIG_NODE, &banner_motd_file_cmd);
paul718e3742002-12-13 20:15:29 +00003572 install_element (CONFIG_NODE, &no_banner_motd_cmd);
3573 install_element (CONFIG_NODE, &service_terminal_length_cmd);
3574 install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
paul718e3742002-12-13 20:15:29 +00003575
paul354d1192005-04-25 16:26:42 +00003576 install_element (VIEW_NODE, &show_thread_cpu_cmd);
3577 install_element (ENABLE_NODE, &show_thread_cpu_cmd);
Paul Jakma62687ff2008-08-23 14:27:06 +01003578 install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
Paul Jakmae276eb82010-01-09 16:15:00 +00003579
3580 install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
paul354d1192005-04-25 16:26:42 +00003581 install_element (VIEW_NODE, &show_work_queues_cmd);
3582 install_element (ENABLE_NODE, &show_work_queues_cmd);
paul9ab68122003-01-18 01:16:20 +00003583 }
paul718e3742002-12-13 20:15:29 +00003584 srand(time(NULL));
3585}
Chris Caputo228da422009-07-18 05:44:03 +00003586
3587void
3588cmd_terminate ()
3589{
3590 unsigned int i, j, k, l;
3591 struct cmd_node *cmd_node;
3592 struct cmd_element *cmd_element;
3593 struct desc *desc;
3594 vector cmd_node_v, cmd_element_v, desc_v;
3595
3596 if (cmdvec)
3597 {
3598 for (i = 0; i < vector_active (cmdvec); i++)
3599 if ((cmd_node = vector_slot (cmdvec, i)) != NULL)
3600 {
3601 cmd_node_v = cmd_node->cmd_vector;
3602
3603 for (j = 0; j < vector_active (cmd_node_v); j++)
3604 if ((cmd_element = vector_slot (cmd_node_v, j)) != NULL &&
3605 cmd_element->strvec != NULL)
3606 {
3607 cmd_element_v = cmd_element->strvec;
3608
3609 for (k = 0; k < vector_active (cmd_element_v); k++)
3610 if ((desc_v = vector_slot (cmd_element_v, k)) != NULL)
3611 {
3612 for (l = 0; l < vector_active (desc_v); l++)
3613 if ((desc = vector_slot (desc_v, l)) != NULL)
3614 {
3615 if (desc->cmd)
3616 XFREE (MTYPE_STRVEC, desc->cmd);
3617 if (desc->str)
3618 XFREE (MTYPE_STRVEC, desc->str);
3619
3620 XFREE (MTYPE_DESC, desc);
3621 }
3622 vector_free (desc_v);
3623 }
3624
3625 cmd_element->strvec = NULL;
3626 vector_free (cmd_element_v);
3627 }
3628
3629 vector_free (cmd_node_v);
3630 }
3631
3632 vector_free (cmdvec);
3633 cmdvec = NULL;
3634 }
3635
3636 if (command_cr)
3637 XFREE(MTYPE_STRVEC, command_cr);
3638 if (desc_cr.str)
3639 XFREE(MTYPE_STRVEC, desc_cr.str);
3640 if (host.name)
3641 XFREE (MTYPE_HOST, host.name);
3642 if (host.password)
3643 XFREE (MTYPE_HOST, host.password);
3644 if (host.password_encrypt)
3645 XFREE (MTYPE_HOST, host.password_encrypt);
3646 if (host.enable)
3647 XFREE (MTYPE_HOST, host.enable);
3648 if (host.enable_encrypt)
3649 XFREE (MTYPE_HOST, host.enable_encrypt);
3650 if (host.logfile)
3651 XFREE (MTYPE_HOST, host.logfile);
3652 if (host.motdfile)
3653 XFREE (MTYPE_HOST, host.motdfile);
3654 if (host.config)
3655 XFREE (MTYPE_HOST, host.config);
3656}